mirror of https://github.com/iotcat/wIoT
Compare commits
2 Commits
d78602c150
...
22779cd6c4
Author | SHA1 | Date |
---|---|---|
呓喵酱 | 22779cd6c4 | 3 years ago |
IoTcat | 91699c5a5c | 3 years ago |
43 changed files with 450 additions and 21039 deletions
@ -1,2 +0,0 @@ |
||||
#!/bin/bash |
||||
.\lib\esptool-ck\esptool.exe -cp COM3 -cd nodemcu -ca 0x00000 -cf .\bin\test.bin |
@ -1,11 +0,0 @@ |
||||
|
||||
--set AP mode |
||||
wifi.setmode(wifi.SOFTAP) |
||||
|
||||
--config AP |
||||
cfg={} |
||||
cfg.ssid="myssid" |
||||
cfg.pwd="mypassword" |
||||
wifi.ap.config(cfg) |
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,2 +0,0 @@ |
||||
#!/bin/bash |
||||
.\node_modules\.bin\nodemcu-tool.cmd run -p COM3 led.lua |
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,11 +0,0 @@ |
||||
{ |
||||
"info": "function() return CONFIG;end", |
||||
"restart": "function() node.restart();end", |
||||
"exec": "function(s) return loadstring(s)();end", |
||||
"list": "function() local obj = {};for k, v in pairs(w.f) do obj[k] = encoder.toHex(crypto.hash([[md5]],string.dump(v))); end;return obj;end", |
||||
"push": "function(s) print(s.hash) w.push(s.hash, s.func);return {status = true};end", |
||||
"pull": "function(s) w.pull(s);return {status = true};end", |
||||
"clear": "function() w.clear();return {status = true};end", |
||||
"refresh": "function() w.refresh();return {status = true};end", |
||||
"test": "function(s) return s end" |
||||
} |
@ -1,15 +0,0 @@ |
||||
{ |
||||
"nid": "good", |
||||
"wifi": { |
||||
"ssid": "yimian-iot", |
||||
"pwd": "1234567890." |
||||
}, |
||||
"msg": { |
||||
"port": 6789 |
||||
}, |
||||
"director": { |
||||
"HeartbeatInterval": 10000, |
||||
"hostname": "192.168.3.100", |
||||
"port": 6789 |
||||
} |
||||
} |
@ -1,134 +0,0 @@ |
||||
-- Wrap a two-staged fifo around a socket's send; see |
||||
-- docs/lua-modules/fifosock.lua for more documentation. |
||||
-- |
||||
-- See fifosocktest.lua for some examples of use or tricky cases. |
||||
-- |
||||
-- Our fifos can take functions; these can be useful for either lazy |
||||
-- generators or callbacks for parts of the stream having been sent. |
||||
|
||||
local BIGTHRESH = 256 -- how big is a "big" string? |
||||
local SPLITSLOP = 16 -- any slop in the big question? |
||||
local FSMALLLIM = 32 -- maximum number of small strings held |
||||
local COALIMIT = 3 |
||||
|
||||
local concat = table.concat |
||||
local insert = table.insert |
||||
local gc = collectgarbage |
||||
|
||||
local function wrap(sock) |
||||
-- the two fifos |
||||
local fsmall, lsmall, fbig = {}, 0, (require "fifo").new() |
||||
|
||||
-- ssend last aggregation string and aggregate count |
||||
local ssla, sslan = nil, 0 |
||||
local ssend = function(s,islast) |
||||
local ns = nil |
||||
|
||||
-- Optimistically, try coalescing FIFO dequeues. But, don't try to |
||||
-- coalesce function outputs, since functions might be staging their |
||||
-- execution on the send event implied by being called. |
||||
|
||||
if type(s) == "function" then |
||||
if sslan ~= 0 then |
||||
sock:send(ssla) |
||||
ssla, sslan = nil, 0; gc() |
||||
return s, false -- stay as is and wait for :on("sent") |
||||
end |
||||
s, ns = s() |
||||
elseif type(s) == "string" and sslan < COALIMIT then |
||||
if sslan == 0 |
||||
then ssla, sslan = s, 1 |
||||
else ssla, sslan = ssla .. s, sslan + 1 |
||||
end |
||||
if islast then |
||||
-- this is shipping; if there's room, steal the small fifo, too |
||||
if sslan < COALIMIT then |
||||
sock:send(ssla .. concat(fsmall)) |
||||
fsmall, lsmall = {}, 0 |
||||
else |
||||
sock:send(ssla) |
||||
end |
||||
ssla, sslan = "", 0; gc() |
||||
return nil, false |
||||
else |
||||
return nil, true |
||||
end |
||||
end |
||||
|
||||
-- Either that was a function or we've hit our coalescing limit or |
||||
-- we didn't ship above. Ship now, if there's something to ship. |
||||
if s ~= nil then |
||||
if sslan == 0 then sock:send(s) else sock:send(ssla .. s) end |
||||
ssla, sslan = nil, 0; gc() |
||||
return ns or nil, false |
||||
elseif sslan ~= 0 then |
||||
assert (ns == nil) |
||||
sock:send(ssla) |
||||
ssla, sslan = nil, 0; gc() |
||||
return nil, false |
||||
else |
||||
assert (ns == nil) |
||||
return nil, true |
||||
end |
||||
end |
||||
|
||||
-- Move fsmall to fbig; might send if fbig empty |
||||
local function promote(f) |
||||
if #fsmall == 0 then return end |
||||
local str = concat(fsmall) |
||||
fsmall, lsmall = {}, 0 |
||||
fbig:queue(str, f or ssend) |
||||
end |
||||
|
||||
local function sendnext() |
||||
if not fbig:dequeue(ssend) then promote() end |
||||
end |
||||
|
||||
sock:on("sent", sendnext) |
||||
|
||||
return function(s) |
||||
-- don't sweat the petty things |
||||
if s == nil or s == "" then return end |
||||
|
||||
-- Function? Go ahead and queue this thing in the right place. |
||||
if type(s) == "function" then promote(); fbig:queue(s, ssend); return; end |
||||
|
||||
s = tostring(s) |
||||
|
||||
-- cork sending until the end in case we're the head of line |
||||
local corked = false |
||||
local function corker(t) corked = true; return t end |
||||
|
||||
-- small fifo would overfill? promote it |
||||
if lsmall + #s > BIGTHRESH or #fsmall >= FSMALLLIM then promote(corker) end |
||||
|
||||
-- big string? chunk and queue big components immediately |
||||
-- behind any promotion that just took place |
||||
while #s > BIGTHRESH + SPLITSLOP do |
||||
local pfx |
||||
pfx, s = s:sub(1,BIGTHRESH), s:sub(BIGTHRESH+1) |
||||
fbig:queue(pfx, corker) |
||||
end |
||||
|
||||
-- Big string? queue and maybe tx now |
||||
if #s > BIGTHRESH then fbig:queue(s, corker) |
||||
-- small and fifo in immediate dequeue mode |
||||
elseif fbig._go and lsmall == 0 then fbig:queue(s, corker) |
||||
-- small and queue already moving; let it linger in the small fifo |
||||
else insert(fsmall, s) ; lsmall = lsmall + #s |
||||
end |
||||
|
||||
-- if it happened that we corked the transmission above... |
||||
-- if we queued a good amount of data, go ahead and start transmitting; |
||||
-- otherwise, wait a tick and hopefully we will queue more in the interim |
||||
-- before transmitting. |
||||
if corked then |
||||
if #fbig <= COALIMIT |
||||
then tmr.create():alarm(1, tmr.ALARM_SINGLE, sendnext) |
||||
else sendnext() |
||||
end |
||||
end |
||||
end |
||||
end |
||||
|
||||
return { wrap = wrap } |
@ -1,9 +0,0 @@ |
||||
{ |
||||
"info": "function() return CONFIG;end", |
||||
"restart": "function() node.restart();end", |
||||
"exec": "function(s) return loadstring(s)();end", |
||||
"list": "function() local obj = {};for k, v in pairs(w.f) do obj[k] = encoder.toHex(crypto.hash([[md5]],string.dump(v))); end;return obj;end", |
||||
"push": "function(s) local obj = sjson.decode(s);w.push(obj.hash, obj.func);return {status = true};end", |
||||
"pull": "function(s) w.pull(s);return {status = true};end", |
||||
"clear": "function() w.clear();return {status = true};end" |
||||
} |
Binary file not shown.
@ -1,217 +0,0 @@ |
||||
------------------------------------------------------------------------------ |
||||
-- HTTP server module |
||||
-- |
||||
-- LICENCE: http://opensource.org/licenses/MIT |
||||
-- Vladimir Dronnikov <dronnikov@gmail.com> |
||||
------------------------------------------------------------------------------ |
||||
local collectgarbage, tonumber, tostring = collectgarbage, tonumber, tostring |
||||
|
||||
local http |
||||
do |
||||
------------------------------------------------------------------------------ |
||||
-- request methods |
||||
------------------------------------------------------------------------------ |
||||
local make_req = function(conn, method, url) |
||||
return { |
||||
conn = conn, |
||||
method = method, |
||||
url = url, |
||||
} |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
-- response methods |
||||
------------------------------------------------------------------------------ |
||||
local make_res = function(csend, cfini) |
||||
local send = function(self, data, status) |
||||
-- TODO: req.send should take care of response headers! |
||||
if self.send_header then |
||||
csend("HTTP/1.1 ") |
||||
csend(tostring(status or 200)) |
||||
-- TODO: real HTTP status code/name table |
||||
csend(" OK\r\n") |
||||
-- we use chunked transfer encoding, to not deal with Content-Length: |
||||
-- response header |
||||
self:send_header("Transfer-Encoding", "chunked") |
||||
-- TODO: send standard response headers, such as Server:, Date: |
||||
end |
||||
if data then |
||||
-- NB: no headers allowed after response body started |
||||
if self.send_header then |
||||
self.send_header = nil |
||||
-- end response headers |
||||
csend("\r\n") |
||||
end |
||||
-- chunked transfer encoding |
||||
csend(("%X\r\n"):format(#data)) |
||||
csend(data) |
||||
csend("\r\n") |
||||
end |
||||
end |
||||
|
||||
local send_header = function(_, name, value) |
||||
-- NB: quite a naive implementation |
||||
csend(name) |
||||
csend(": ") |
||||
csend(value) |
||||
csend("\r\n") |
||||
end |
||||
-- finalize request, optionally sending data |
||||
local finish = function(self, data, status) |
||||
-- NB: res.send takes care of response headers |
||||
if data then |
||||
self:send(data, status) |
||||
end |
||||
-- finalize chunked transfer encoding |
||||
csend("0\r\n\r\n") |
||||
-- close connection |
||||
cfini() |
||||
end |
||||
-- |
||||
local res = { } |
||||
res.send_header = send_header |
||||
res.send = send |
||||
res.finish = finish |
||||
return res |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
-- HTTP parser |
||||
------------------------------------------------------------------------------ |
||||
local http_handler = function(handler) |
||||
return function(conn) |
||||
local csend = (require "fifosock").wrap(conn) |
||||
|
||||
local req, res |
||||
local buf = "" |
||||
local method, url |
||||
|
||||
local ondisconnect = function(connection) |
||||
connection:on("receive", nil) |
||||
connection:on("disconnection", nil) |
||||
connection:on("sent", nil) |
||||
collectgarbage("collect") |
||||
end |
||||
|
||||
local cfini = function() |
||||
csend(function() |
||||
conn:on("sent", nil) |
||||
conn:close() |
||||
ondisconnect(conn) |
||||
end) |
||||
end |
||||
|
||||
|
||||
-- header parser |
||||
local cnt_len = 0 |
||||
|
||||
local onheader = function(_, k, v) |
||||
-- TODO: look for Content-Type: header |
||||
-- to help parse body |
||||
-- parse content length to know body length |
||||
if k == "content-length" then |
||||
cnt_len = tonumber(v) |
||||
end |
||||
if k == "expect" and v == "100-continue" then |
||||
csend("HTTP/1.1 100 Continue\r\n") |
||||
end |
||||
-- delegate to request object |
||||
if req and req.onheader then |
||||
req:onheader(k, v) |
||||
end |
||||
end |
||||
|
||||
-- body data handler |
||||
local body_len = 0 |
||||
local ondata = function(_, chunk) |
||||
-- feed request data to request handler |
||||
if not req or not req.ondata then return end |
||||
req:ondata(chunk) |
||||
-- NB: once length of seen chunks equals Content-Length: |
||||
-- ondata(conn) is called |
||||
body_len = body_len + #chunk |
||||
-- print("-B", #chunk, body_len, cnt_len, node.heap()) |
||||
if body_len >= cnt_len then |
||||
req:ondata() |
||||
end |
||||
end |
||||
|
||||
local onreceive = function(connection, chunk) |
||||
-- merge chunks in buffer |
||||
if buf then |
||||
buf = buf .. chunk |
||||
else |
||||
buf = chunk |
||||
end |
||||
-- consume buffer line by line |
||||
while #buf > 0 do |
||||
-- extract line |
||||
local e = buf:find("\r\n", 1, true) |
||||
if not e then break end |
||||
local line = buf:sub(1, e - 1) |
||||
buf = buf:sub(e + 2) |
||||
-- method, url? |
||||
if not method then |
||||
do |
||||
local _ |
||||
-- NB: just version 1.1 assumed |
||||
_, _, method, url = line:find("^([A-Z]+) (.-) HTTP/1.1$") |
||||
end |
||||
if method then |
||||
-- make request and response objects |
||||
req = make_req(connection, method, url) |
||||
res = make_res(csend, cfini) |
||||
end |
||||
-- spawn request handler |
||||
handler(req, res) |
||||
-- header line? |
||||
elseif #line > 0 then |
||||
-- parse header |
||||
local _, _, k, v = line:find("^([%w-]+):%s*(.+)") |
||||
-- header seems ok? |
||||
if k then |
||||
k = k:lower() |
||||
onheader(connection, k, v) |
||||
end |
||||
-- headers end |
||||
else |
||||
-- NB: we explicitly reassign receive handler so that |
||||
-- next received chunks go directly to body handler |
||||
connection:on("receive", ondata) |
||||
-- NB: we feed the rest of the buffer as starting chunk of body |
||||
ondata(connection, buf) |
||||
-- buffer no longer needed |
||||
buf = nil |
||||
-- parser done |
||||
break |
||||
end |
||||
end |
||||
end |
||||
|
||||
conn:on("receive", onreceive) |
||||
conn:on("disconnection", ondisconnect) |
||||
end |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
-- HTTP server |
||||
------------------------------------------------------------------------------ |
||||
local srv |
||||
local createServer = function(port, handler) |
||||
-- NB: only one server at a time |
||||
if srv then srv:close() end |
||||
srv = net.createServer(net.TCP, 15) |
||||
-- listen |
||||
srv:listen(port, http_handler(handler)) |
||||
return srv |
||||
end |
||||
|
||||
------------------------------------------------------------------------------ |
||||
-- HTTP server methods |
||||
------------------------------------------------------------------------------ |
||||
http = { |
||||
createServer = createServer, |
||||
} |
||||
end |
||||
|
||||
return http |
Binary file not shown.
@ -1,12 +0,0 @@ |
||||
if file.exists('_lfs.img') then |
||||
file.remove('_lfs.img'); |
||||
elseif file.exists('lfs.img') then |
||||
file.rename('lfs.img', '_lfs.img'); |
||||
node.LFS.reload('_lfs.img'); |
||||
end |
||||
if adc.force_init_mode(adc.INIT_ADC) |
||||
then |
||||
node.restart() |
||||
return |
||||
end |
||||
node.LFS.wiot() |
@ -1,271 +0,0 @@ |
||||
--Global Var |
||||
CONFIG = {} |
||||
udp = nil --UDP Server |
||||
key = nil --Encrypt Key |
||||
G = {} --Var Zone |
||||
|
||||
--wIoT Toolbox |
||||
w = { |
||||
f = {}, |
||||
waitList = {}, |
||||
send = function(ip, port, fid, body, cb) |
||||
local sid = func.randomLetter(8) |
||||
local o = { |
||||
fid = fid, |
||||
sid = sid, |
||||
id = CONFIG.w.id, |
||||
body = body |
||||
} |
||||
local status, msg = pcall(sjson.encode, o) |
||||
udp:send(port, ip, msg) |
||||
if cb == nil then return ;end |
||||
w.waitList[sid] = false |
||||
local resTimer = tmr.create() |
||||
local retryTimer = tmr.create() |
||||
local retryTimes = CONFIG.w.maxRetryTimes |
||||
resTimer:register(CONFIG.w.scanInterval, tmr.ALARM_AUTO, function() |
||||
if func.tableKeyExist(w.waitList, sid) and w.waitList[sid] ~= false then |
||||
cb(w.waitList[sid]) |
||||
w.waitList[sid] = nil |
||||
resTimer:unregister() |
||||
retryTimer:unregister() |
||||
collectgarbage("collect") |
||||
end |
||||
end) |
||||
retryTimer:register(CONFIG.w.retryInterval, tmr.ALARM_AUTO, function() |
||||
if retryTimes > 0 and func.tableKeyExist(w.waitList, sid) and w.waitList[sid] == false then |
||||
udp:send(port, ip, msg) |
||||
retryTimes = retryTimes - 1 |
||||
else |
||||
retryTimer:unregister() |
||||
collectgarbage("collect") |
||||
end |
||||
end) |
||||
resTimer:start() |
||||
retryTimer:start() |
||||
end, |
||||
receive = function(s, data, port, ip) |
||||
print(data) |
||||
local status, msg = pcall(sjson.decode, data) |
||||
if not status then return end |
||||
if not func.tableKeyExist(msg, 'sid') or not func.tableKeyExist(msg, 'body') then return end |
||||
--respond mode |
||||
print(msg.fid) |
||||
if not func.tableKeyExist(msg, 'fid') then |
||||
if func.tableKeyExist(w.waitList, msg.sid) then |
||||
w.waitList[msg.sid] = msg.body |
||||
end |
||||
return |
||||
end |
||||
print(msg.fid) |
||||
--request mode |
||||
if not func.tableKeyExist(w.f, msg.fid) then return end |
||||
local res = w.f[msg.fid](msg.body, {port = port, ip = ip, socket = s, sid = msg.sid, fid = msg.fid}); |
||||
print(msg.fid) |
||||
local resObj = { |
||||
sid = msg.sid, |
||||
id = CONFIG.w.id, |
||||
body = res |
||||
} |
||||
status, res = pcall(sjson.encode, resObj) |
||||
print(res) |
||||
s:send(port, ip, res) |
||||
end, |
||||
heartbeat = function() |
||||
local o = { |
||||
version = CONFIG.firmware.version, |
||||
id = CONFIG.w.id, |
||||
ip = wifi.sta.getip(), |
||||
port = CONFIG.udp.server.port, |
||||
} |
||||
--request |
||||
print(sjson.encode(o)) |
||||
udp:send(CONFIG.w.director.port, CONFIG.w.director.ip, sjson.encode(o)) |
||||
end, |
||||
_push = function(hash, s) |
||||
w.f[hash] = function(r) |
||||
if hash == 'construct' or hash == 'destruct' then |
||||
print(s) |
||||
loadstring('print("hhhhhhh")')() |
||||
loadstring(s)() |
||||
return |
||||
end |
||||
local status, msg = pcall(loadstring('return '..s)(), r) |
||||
local data = { |
||||
status = status, |
||||
data = msg |
||||
} |
||||
return data |
||||
end |
||||
return hash |
||||
end, |
||||
push = function(hash, s) |
||||
w._push(hash, s) |
||||
func.jsonfPush('func.json', hash, s) |
||||
return hash |
||||
end, |
||||
pull = function(hash) |
||||
w.f[hash] = nil |
||||
func.jsonfPull('func.json', hash) |
||||
w.refresh() |
||||
end, |
||||
clear = function() |
||||
func.jsonfClear('func.json') |
||||
w.refresh() |
||||
end, |
||||
start = function() |
||||
print('w starting...') |
||||
local usr = func.jsonfRead('func.json') |
||||
if next(usr) ~= nil then |
||||
print('in usr') |
||||
for k, v in pairs(usr) do |
||||
print(k) |
||||
w._push(k, v) |
||||
end |
||||
else |
||||
print('in systemd') |
||||
local systemd = func.jsonfRead('FUNC.json') |
||||
for k, v in pairs(systemd) do |
||||
print(k) |
||||
w.push(k, v) |
||||
end |
||||
end |
||||
if func.tableKeyExist(w.f, 'construct') then |
||||
w.f:construct() |
||||
end |
||||
end, |
||||
stop = function() |
||||
if func.tableKeyExist(w.f, 'destruct') then |
||||
w.f:destruct() |
||||
end |
||||
w.f = {} |
||||
collectgarbage("collect") |
||||
end, |
||||
refresh = function() |
||||
pcall(w.stop) |
||||
pcall(w.start) |
||||
end |
||||
} |
||||
|
||||
--Functions |
||||
func = { |
||||
init = { |
||||
run = function() |
||||
if file.exists("__running") then |
||||
file.rename("__running", "__stopped") |
||||
else |
||||
func.jsonfClear('func.json') |
||||
end |
||||
collectgarbage("collect") |
||||
w.start() |
||||
collectgarbage("collect") |
||||
func.init.wifi(func.init.udp, func.init.w, func.run) |
||||
end, |
||||
wifi = function(after, after2, after3) |
||||
print('Setting up WIFI...') |
||||
wifi.setmode(wifi.STATION) |
||||
wifi.sta.config(CONFIG.wifi.station) |
||||
wifi.sta.connect() |
||||
local wifiInit = tmr.create() |
||||
wifiInit:register(1000, tmr.ALARM_AUTO, function() |
||||
if wifi.sta.getip() == nil then |
||||
print('Waiting for IP ...') |
||||
else |
||||
print('IP is ' .. wifi.sta.getip()) |
||||
wifiInit:unregister() |
||||
after(after2, after3) |
||||
end |
||||
end) |
||||
wifiInit:start() |
||||
end, |
||||
udp = function (after, after2) |
||||
udp = net.createUDPSocket() |
||||
udp:listen(CONFIG.udp.server.port) |
||||
udp:on("receive", w.receive) |
||||
after(after2) |
||||
end, |
||||
w = function(after) |
||||
w.heartbeat() |
||||
local heartbeat = tmr.create() |
||||
heartbeat:register(CONFIG.w.heartbeat.interval, tmr.ALARM_AUTO, function() |
||||
w.heartbeat() |
||||
file.rename("__stopped", "__running") |
||||
end); |
||||
heartbeat:start() |
||||
if after then after() end |
||||
end |
||||
}, |
||||
randomLetter = function(len) |
||||
local rt = "" |
||||
for i = 1, len, 1 do |
||||
rt = rt..string.char(math.random(97,122)) |
||||
end |
||||
return rt |
||||
end, |
||||
jsonfRead = function(f) |
||||
if file.open(f) then |
||||
local status, obj = pcall(sjson.decode, file.read()) |
||||
file.close() |
||||
if status then |
||||
return obj |
||||
else |
||||
return {} |
||||
end |
||||
end |
||||
return {} |
||||
end, |
||||
jsonfWrite = function(f, obj) |
||||
if file.open(f, 'w+') then |
||||
local status, json = pcall(sjson.encode, obj) |
||||
if status then |
||||
file.write(json) |
||||
else |
||||
file.write("{}") |
||||
end |
||||
file.close() |
||||
end |
||||
end, |
||||
jsonfPush = function(f, hash, s) |
||||
local obj = func.jsonfRead(f) |
||||
obj[hash] = s |
||||
func.jsonfWrite(f, obj) |
||||
end, |
||||
jsonfPull = function(f, hash) |
||||
func.jsonfPush(f, hash, nil) |
||||
end, |
||||
jsonfClear = function(f) |
||||
func.jsonfWrite(f, {}) |
||||
end, |
||||
encrypt = function(s, kay) |
||||
if key == nil then return s;end |
||||
local msg = encoder.toHex(crypto.encrypt("AES-ECB", key, s..func.randomLetter(4))) |
||||
return msg..string.sub(encoder.toHex(crypto.hmac("sha1", msg, key)), 1, 8) |
||||
end, |
||||
decrypt = function(s, kay) |
||||
if key == nil then return s;end |
||||
local msg, hmac = string.sub(s, 1, string.len(s)-8), string.sub(s, string.len(s)-7, 8) |
||||
if string.sub(encoder.toHex(crypto.hmac("sha1", msg, key)), 1, 8) ~= hmac then return nil; end |
||||
local raw = crypto.decrypt("AES-ECB", key, encoder.fromHex(msg)) |
||||
return string.sub(raw, 1, string.len(raw) - 4) |
||||
end, |
||||
tableKeyExist = function(obj, key) |
||||
for k, v in pairs(obj) do |
||||
if k == key then |
||||
return true |
||||
end |
||||
end |
||||
return false |
||||
end |
||||
} |
||||
|
||||
--Run |
||||
func.run = function() |
||||
--run content |
||||
gpio.write(0, gpio.LOW) |
||||
end |
||||
|
||||
--Load CONFIG |
||||
CONFIG = func.jsonfRead('config.json') |
||||
|
||||
--exec Init |
||||
func.init.run() |
@ -1,842 +0,0 @@ |
||||
tmr.delay(3000000); |
||||
print('total'..node.heap()); |
||||
(function(__run) |
||||
--Packages Used: file, sjson, http, httpserver, mqtt, encoder, timer, node, wifi, gpio |
||||
print('close'..node.heap()) |
||||
|
||||
--Global Methods |
||||
--------------- |
||||
-- File Object Operation |
||||
local f = {}; |
||||
--f |
||||
f.read = function(f)--f:filename |
||||
local status, obj = pcall(sjson.decode, file.getcontents(f)); |
||||
if status then |
||||
return obj; |
||||
else |
||||
return {}; |
||||
end |
||||
end |
||||
f.write = function(f, obj) |
||||
local status, json = pcall(sjson.encode, obj); |
||||
if status then |
||||
return file.putcontents(f, json); |
||||
else |
||||
return false; |
||||
end |
||||
end |
||||
--split string |
||||
local stringSplit = function(str, reps) |
||||
local resultStrList = {} |
||||
string.gsub(str,'[^'..reps..']+', function (w) |
||||
table.insert(resultStrList,w); |
||||
end); |
||||
return resultStrList; |
||||
end |
||||
|
||||
--Method Declaration |
||||
-------------------- |
||||
_ = { |
||||
_ = { |
||||
restart = nil, |
||||
reset = nil |
||||
}, |
||||
init = { |
||||
http = nil, |
||||
mqtt = nil, |
||||
onlineFunc = nil |
||||
}, |
||||
config = { |
||||
v = nil, |
||||
path = 'config.json', |
||||
default = { |
||||
nid = 'default', |
||||
offlineOnly = true, |
||||
signalPin = 0, |
||||
flag = { |
||||
MaxRetryTimes = 2, |
||||
MaxResetTimes = 3 |
||||
}, |
||||
func = { |
||||
offline = { |
||||
MaxWaitTime = 60 |
||||
}, |
||||
online = { |
||||
MaxWaitTime = 60 |
||||
} |
||||
}, |
||||
fs = { |
||||
prefix = { |
||||
root = '', |
||||
system = '__system/', |
||||
data = '__data/', |
||||
swap = '__system/swap/' |
||||
}, |
||||
filename = { |
||||
nsmap = 'ns.map', |
||||
flag = 'flag', |
||||
func = 'func.json', |
||||
error = 'error.json' |
||||
} |
||||
}, |
||||
wifi = { |
||||
CheckInterval = 1000, |
||||
config = { |
||||
ssid = '', |
||||
pwd = '', |
||||
save = false |
||||
} |
||||
}, |
||||
http = { |
||||
port = 6789, |
||||
api = { |
||||
discover = '/discover' |
||||
} |
||||
}, |
||||
mqtt = { |
||||
host = 'mqtt.yimian.xyz', |
||||
port = 1883, |
||||
user = nil, |
||||
password = nil, |
||||
tls = false, |
||||
keepaliveTimer = 30, |
||||
topicPrefix = '/wiot/default/', |
||||
ConnectRetryInterval = 2000, |
||||
OfflineRetryInterval = 3000, |
||||
PostCheckInterval = 100, |
||||
PostTimeout = 10 |
||||
} |
||||
} |
||||
}, |
||||
flag = { |
||||
v = nil, |
||||
set = nil, |
||||
load = nil |
||||
}, |
||||
func = { |
||||
id = nil, |
||||
offline = nil, |
||||
online = nil |
||||
}, |
||||
table = { |
||||
merge = nil |
||||
}, |
||||
timer = { |
||||
setTimeout = nil, |
||||
setInterval = nil |
||||
}, |
||||
signal = { |
||||
init = nil, |
||||
set = nil, |
||||
destroy = nil, |
||||
v = nil |
||||
}, |
||||
http = { |
||||
v = nil |
||||
}, |
||||
mqtt = { |
||||
getTopic = nil, |
||||
v = nil |
||||
}, |
||||
f = { |
||||
read = nil, |
||||
write = nil |
||||
}, |
||||
ns = { |
||||
set = nil, |
||||
get = nil, |
||||
render = nil, |
||||
exist = nil, |
||||
check = nil, |
||||
verify = nil |
||||
}, |
||||
package = { |
||||
pack = nil, |
||||
depack = nil, |
||||
set = nil, |
||||
get = nil |
||||
}, |
||||
db = { |
||||
public = { |
||||
keys = nil, |
||||
get = nil, |
||||
set = nil, |
||||
del = nil, |
||||
clear = nil |
||||
}, |
||||
toIndex = nil, |
||||
fromIndex = nil, |
||||
getFileName = nil |
||||
}, |
||||
msg = { |
||||
reg = { |
||||
send = {}, |
||||
post = {} |
||||
}, |
||||
postWaitList = {}, |
||||
public = { |
||||
post = nil, |
||||
send = nil, |
||||
onPost = nil, |
||||
onSend = nil |
||||
}, |
||||
mpost = nil, |
||||
msend = nil, |
||||
dpost = nil, |
||||
dsend = nil |
||||
}, |
||||
api = { |
||||
http = { |
||||
discover = nil, |
||||
msg = nil |
||||
}, |
||||
mqtt = { |
||||
msg = nil, |
||||
heartbeat = nil, |
||||
ns = nil, |
||||
func = nil, |
||||
restart = nil |
||||
} |
||||
} |
||||
}; |
||||
|
||||
print('_.all'..node.heap()) |
||||
print(_.config.default.nid); |
||||
|
||||
|
||||
local CONFIG_DEFAULT = { |
||||
nid = 'default', |
||||
offlineOnly = true, |
||||
signalPin = 0, |
||||
flag = { |
||||
MaxRetryTimes = 2, |
||||
MaxResetTimes = 3 |
||||
}, |
||||
func = { |
||||
offline = { |
||||
MaxWaitTime = 60 |
||||
}, |
||||
online = { |
||||
MaxWaitTime = 60 |
||||
} |
||||
}, |
||||
fs = { |
||||
prefix = { |
||||
root = '', |
||||
system = '__system/', |
||||
data = '__data/', |
||||
swap = '__system/swap/' |
||||
}, |
||||
filename = { |
||||
nsmap = 'ns.map', |
||||
flag = 'flag', |
||||
func = 'func.json', |
||||
error = 'error.json' |
||||
} |
||||
}, |
||||
wifi = { |
||||
CheckInterval = 1000, |
||||
config = { |
||||
ssid = '', |
||||
pwd = '', |
||||
save = false |
||||
} |
||||
}, |
||||
http = { |
||||
port = 6789, |
||||
api = { |
||||
discover = '/discover' |
||||
} |
||||
}, |
||||
mqtt = { |
||||
host = 'mqtt.yimian.xyz', |
||||
port = 1883, |
||||
user = nil, |
||||
password = nil, |
||||
tls = false, |
||||
keepaliveTimer = 30, |
||||
topicPrefix = '/wiot/default/', |
||||
ConnectRetryInterval = 2000, |
||||
OfflineRetryInterval = 3000, |
||||
PostCheckInterval = 100, |
||||
PostTimeout = 10 |
||||
} |
||||
} |
||||
|
||||
|
||||
--Merge config |
||||
---------------------- |
||||
--Methods preparation |
||||
-- merge two tables |
||||
tableMerge = function(a, b) |
||||
for k, v in pairs(b) do |
||||
if type(v) == 'table' and type(a[k] or false) == 'table' then |
||||
a[k] = tableMerge(a[k], v); |
||||
else |
||||
a[k] = v; |
||||
end |
||||
end |
||||
return a; |
||||
end |
||||
print('merge.p'..node.heap()) |
||||
--Exec |
||||
_.config.v = _.config.default; |
||||
_.config.v = tableMerge(_.config.v, f.read(_.config.path)); |
||||
print('merge.e'..node.heap()) |
||||
--Release Resources |
||||
tableMerge = nil; |
||||
fRead = nil; |
||||
collectgarbage("collect"); |
||||
print(_.config.v.wifi.config.ssid) |
||||
print(_.config.v.mqtt.host) |
||||
print('merge.r'..node.heap()) |
||||
|
||||
|
||||
--Load SWAP |
||||
----------- |
||||
--Methods Preparation |
||||
Load_ToSwap = function(obj, s) |
||||
print('swap.p'..node.heap()..s) |
||||
for k, v in pairs(_) do |
||||
s = s..'_'..encoder.toBase64(k); |
||||
if type(v) == 'table' then |
||||
Load_ToSwap(v, s); |
||||
else |
||||
file.putcontents(_.config.v.fs.prefix.swap..s, v); |
||||
end |
||||
end |
||||
end |
||||
print('swap.p'..node.heap()) |
||||
-- Exec |
||||
Load_ToSwap(_.config.v, encoder.toBase64('config')..'_'..encoder.toBase64('v')); |
||||
local SWAP_PREFIX = _.config.v.fs.prefix.swap; |
||||
print('swap.e'..node.heap()) |
||||
--Release Resources |
||||
Load_ToSwap = nil; |
||||
_ = nil; |
||||
print('swap.r'..node.heap()) |
||||
--Global APIs |
||||
_ = setmetaltable({}, { |
||||
__index = function(table, key) |
||||
local arr = stringSplit(key, '_'); |
||||
local s = ''; |
||||
for v in arr do |
||||
s = s..'_'..encoder.toBase64(v); |
||||
end |
||||
return file.getcontents(SWAP_PREFIX..s); |
||||
end, |
||||
__newindex = function(table, key, val) |
||||
local arr = stringSplit(key, '_'); |
||||
local s = ''; |
||||
for v in arr do |
||||
s = s..'_'..encoder.toBase64(v); |
||||
end |
||||
if type(val) == 'function' then |
||||
val = string.dump(val); |
||||
end |
||||
file.putcontents(SWAP_PREFIX..s, val); |
||||
end |
||||
}); |
||||
print('swap.a'..node.heap()) |
||||
print(_.config_v_nid); |
||||
|
||||
|
||||
--package loaded |
||||
---------------- |
||||
local httpserver = dofile('httpserver.lua'); |
||||
|
||||
|
||||
--Method Defination |
||||
------------------- |
||||
--_ |
||||
_._.restart = function(err) |
||||
if err then |
||||
file.putcontents(_.config.v.fs.prefix.system.._.config.v.fs.filename.error, tostring(err)); |
||||
end |
||||
node.restart(); |
||||
end |
||||
_._.reset = function() |
||||
file.remove(_.config.v.fs.prefix.system.._.config.v.fs.filename.error); |
||||
file.remove(_.config.v.fs.prefix.system.._.config.v.fs.filename.func); |
||||
file.remove(_.config.v.fs.prefix.system.._.config.v.fs.filename.flag); |
||||
node.restart(); |
||||
end |
||||
|
||||
--flag |
||||
_.flag.load = function() |
||||
_.flag.v = tonumber(file.getcontents(_.config.v.fs.prefix.system.._.config.v.fs.filename.flag)); |
||||
end |
||||
_.flag.set = function(val) |
||||
_.config.flag.v = val; |
||||
file.putcontents(_.config.v.fs.prefix.system.._.config.v.fs.filename.flag, tostring(val)); |
||||
end |
||||
_.flag.ward = function(f) |
||||
f(); |
||||
_.flag.set(-1); |
||||
end |
||||
--table |
||||
|
||||
--timer |
||||
_.timer.setTimeout = function(f, time_ms) |
||||
return tmr.create():alarm(time_ms, tmr.ALARM_SINGLE, f); |
||||
end |
||||
_.timer.setInterval = function(f, time_ms) |
||||
return tmr.create():alarm(time_ms, tmr.ALARM_AUTO, function(timer) |
||||
f(function(delay_time_ms) |
||||
if delay_time_ms < 0 then |
||||
timer:unregister(); |
||||
else |
||||
timer:stop(); |
||||
_.timer.setTimeout(function() |
||||
timer:start(); |
||||
end, delay_time_ms); |
||||
end |
||||
end) |
||||
end); |
||||
end |
||||
|
||||
--signal |
||||
_.signal.init = function() |
||||
gpio.mode(_.config.v.signalPin, gpio.OUTPUT); |
||||
_.signal.v = tmr.create(); |
||||
end |
||||
_.signal.set = function(interval_ms) |
||||
_.signal.v:alarm(interval_ms, tmr.ALARM_AUTO, function() |
||||
if gpio.read(_.config.v.signalPin) == gpio.HIGH then |
||||
gpio.write(_.config.v.signalPin, gpio.LOW); |
||||
else |
||||
gpio.write(_.config.v.signalPin, gpio.HIGH); |
||||
end |
||||
end); |
||||
end |
||||
_.signal.destroy = function() |
||||
gpio.write(_.config.v.signalPin, gpio.HIGH); |
||||
_.signal.v:unregister(); |
||||
_.signal.v = nil; |
||||
end |
||||
|
||||
--mqtt |
||||
_.mqtt.getTopic = function(s) |
||||
return _.config.v.mqtt.topicPrefix.._.config.v.nid..'/'..s; |
||||
end |
||||
_.mqtt.start = function() |
||||
_.mqtt.v:connect( |
||||
_.config.v.mqtt.host, |
||||
_.config.v.mqtt.port, |
||||
_.config.v.mqtt.tls, |
||||
function(client) |
||||
client:subscribe(_.mqtt.getTopic('msg/#')); |
||||
client:subscribe(_.mqtt.getTopic('ctl/#')); |
||||
client:publish(_.mqtt.getTopic('status'), 'online', 0, 0); |
||||
end, |
||||
function(client, reason) |
||||
_.timer.setTimeout(_.mqtt.start, _.config.v.mqtt.ConnectRetryInterval); |
||||
end |
||||
); |
||||
end |
||||
|
||||
|
||||
|
||||
--ns |
||||
_.ns.set = function(obj) |
||||
return _.f.write(_.config.v.fs.prefix.system.._.config.v.fs.filename.nsmap, obj); |
||||
end |
||||
_.ns.get = function() |
||||
return _.f.read(_.config.v.fs.prefix.system.._.config.v.fs.filename.nsmap); |
||||
end |
||||
_.ns.render = function(nid) |
||||
for k, v in pairs(_.ns.get()) do |
||||
if k == nid and v then |
||||
return v; |
||||
end |
||||
end |
||||
return nid; |
||||
end |
||||
_.ns.exist = function(nid) |
||||
if _.ns.render(nid) == nid then |
||||
return false; |
||||
else |
||||
return true; |
||||
end |
||||
end |
||||
_.ns.check = function(nid, ip, cb)--cb:bool status |
||||
http.post('http://'..ip.._.config.v.http.api.discover, nil, '', function(code, data) |
||||
if code ~= 200 or data ~= nid then |
||||
cb(false); |
||||
else |
||||
cb(true); |
||||
end |
||||
end); |
||||
end |
||||
_.ns.verify = function() |
||||
local ns = _.ns.get(); |
||||
for k, v in pairs(ns) do |
||||
_.ns.check(k, v, function(status) |
||||
if not status then |
||||
ns[k] = false; |
||||
_.ns.set(ns); |
||||
end |
||||
end) |
||||
end |
||||
end |
||||
|
||||
--package |
||||
_.package.pack = function(o) |
||||
local status, json = pcall(sjson.encode, o); |
||||
if status then |
||||
return json; |
||||
else |
||||
return nil; |
||||
end |
||||
end |
||||
_.package.depack = function(s) |
||||
local status, obj = pcall(json.decode, s); |
||||
if status then |
||||
return obj; |
||||
else |
||||
return {}; |
||||
end |
||||
end |
||||
_.package.set = function(to, body, mode)--to:nid, body:obj |
||||
local o = { |
||||
from = _.config.v.nid, |
||||
to = to, |
||||
mode = mode, |
||||
body = body |
||||
} |
||||
return _.package.pack(o); |
||||
end |
||||
_.package.get = function(pack)--string package |
||||
local status, obj = pcall(json.decode, pack); |
||||
if status and obj.from and obj.mode then |
||||
return obj.from, obj.body, obj.mode; |
||||
else |
||||
return nil, nil, nil; |
||||
end |
||||
end |
||||
|
||||
--db |
||||
_.db.toIndex = function(key) |
||||
return encoder.toBase64(key); |
||||
end |
||||
_.db.fromIndex = function(index) |
||||
return encoder.fromBase64(index); |
||||
end |
||||
_.db.getFileName = function(key) |
||||
return _.config.v.fs.prefix.data.._.db.toIndex(key); |
||||
end |
||||
_.db.public.keys = function() --list all keys with size |
||||
local o = {}; |
||||
for k, v in pairs(file.list(_.config.v.fs.prefix.data..'.')) do |
||||
o[_.db.fromIndex(k)] = v; |
||||
end |
||||
return o; |
||||
end |
||||
_.db.public.get = function(key) |
||||
return _.f.read(); |
||||
end |
||||
_.db.public.set = function(key, obj) |
||||
return _.f.write(_.db.getFileName(key), obj); |
||||
end |
||||
_.db.public.del = function(key) |
||||
local fileName = _.db.getFileName(key); |
||||
file.remove(fileName); |
||||
return not file.exists(fileName); |
||||
end |
||||
_.db.public.clear = function() |
||||
local flag = true; |
||||
for k, v in pairs(_.db.public.keys()) do |
||||
flag = flag and _.db.public.del(k); |
||||
end |
||||
return flag; |
||||
end |
||||
|
||||
--msg |
||||
_.msg.dpost = function(to, name, body, cb)--return (bool status, data) |
||||
if _.ns.exist(to) then |
||||
http.post( |
||||
'http://'.._.ns.render(to)..'/msg/'..encoder.toBase64(name), |
||||
'Content-Type: application/json\r\n', |
||||
_.package.set(to, body, 'post'), |
||||
function(code, res) |
||||
if code ~= 200 then |
||||
cb(false); |
||||
else |
||||
cb(true, _.package.get(res)); |
||||
end |
||||
end |
||||
); |
||||
else |
||||
cb(false); |
||||
end |
||||
end |
||||
_.msg.dsend = function(to, name, body) |
||||
if _.ns.exist(to) then |
||||
http.post( |
||||
'http://'.._.ns.render(to)..'/msg/'..encoder.toBase64(name), |
||||
'Content-Type: application/json\r\n', |
||||
_.package.set(to, body, 'send'), |
||||
function(code, res) end |
||||
); |
||||
end |
||||
end |
||||
_.msg.mpost = function(to, name, body, cb) |
||||
_.msg.postWaitList[encoder.toBase64(name)..to] = false; |
||||
local PostBeginAt = tmr.time(); |
||||
_.timer.setInterval(function(delay) |
||||
if _.msg.postWaitList[encoder.toBase64(name)..to] ~= false then |
||||
cb(true, _.msg.postWaitList[encoder.toBase64(name)..to]); |
||||
_.msg.postWaitList[encoder.toBase64(name)..to] = nil; |
||||
delay(-1); |
||||
else |
||||
if PostBeginAt < tmr.time() - _.config.v.mqtt.PostTimeout then |
||||
cb(false); |
||||
_.msg.postWaitList[encoder.toBase64(name)..to] = nil; |
||||
delay(-1); |
||||
end |
||||
end |
||||
end, _.config.v.mqtt.PostCheckInterval); |
||||
_.mqtt.v:publish( |
||||
_.config.v.mqtt.topicPrefix..to..'/'..encoder.toBase64(name), |
||||
_.package.set(to, body, 'post'), |
||||
1, |
||||
0 |
||||
); |
||||
end |
||||
_.msg.msend = function(to, name, body) |
||||
_.mqtt.v:publish( |
||||
_.config.v.mqtt.topicPrefix..to..'/'..encoder.toBase64(name), |
||||
_.package.set(to, body, 'send'), |
||||
0, |
||||
0 |
||||
); |
||||
end |
||||
_.msg.public.onSend = function(name, f)--f:return (body, from) |
||||
_.msg.reg.send[encoder.toBase64(name)] = f; |
||||
end |
||||
_.msg.public.onPost = function(name, f)--f:return body, from, reply(reply_body) |
||||
_.msg.reg.post[encoder.toBase64(name)] = f; |
||||
end |
||||
_.msg.public.send = function(to, name, body) |
||||
if _.ns.exist(to) then |
||||
_.msg.dsend(to, name, body); |
||||
else |
||||
_.msg.msend(to, name, body); |
||||
end |
||||
end |
||||
_.msg.public.post = function(to, name, body, cb) |
||||
if _.ns.exist(to) then |
||||
_.msg.dpost(to, name, body, cb); |
||||
else |
||||
_.msg.mpost(to, name, body, cb); |
||||
end |
||||
end |
||||
|
||||
--api |
||||
_.api.http.discover = function(res) |
||||
res.finish(_.config.v.nid, 200); |
||||
end |
||||
_.api.http.msg = function(name, req, res) |
||||
local data = ''; |
||||
req.ondata = function(req, chunk) |
||||
if chunk ~= nil then |
||||
data = data..chunk; |
||||
else |
||||
local from, body, mode = _.package.get(data); |
||||
if mode == 'send' then |
||||
res.finish(); |
||||
for k, v in pairs(_.msg.reg.send) do |
||||
if k == name then |
||||
v(body, from); |
||||
return; |
||||
end |
||||
end |
||||
elseif mode == 'post' then |
||||
for k, v in pairs(_.msg.reg.post) do |
||||
if k == name then |
||||
v(body, from, function(reply_body) |
||||
res.finish(_.package.set(from, reply_body, 'reply')); |
||||
end); |
||||
return; |
||||
end |
||||
end |
||||
res.finish(nil, 404); |
||||
end |
||||
end |
||||
end |
||||
end |
||||
_.api.mqtt.msg = function(name, data) |
||||
local from, body, mode = _.package.get(data); |
||||
if mode == 'send' then |
||||
for k, v in pairs(_.msg.reg.send) do |
||||
if k == name then |
||||
v(body, from); |
||||
return; |
||||
end |
||||
end |
||||
elseif mode == 'post' then |
||||
for k, v in pairs(_.msg.reg.post) do |
||||
if k == name then |
||||
v(body, from, function(reply_body) |
||||
_.mqtt.v:publish(_.config.v.mqtt.topicPrefix..from..'/msg/'..name.._.config.v.nid, _.package.set(from, reply_body, 'reply'), 1, 0); |
||||
end); |
||||
return; |
||||
end |
||||
end |
||||
elseif mode == 'reply' then |
||||
for k, v in pairs(_.msg.postWaitList) do |
||||
if k == name then |
||||
_.msg.postWaitList[k] = body; |
||||
return; |
||||
end |
||||
end |
||||
end |
||||
end |
||||
_.api.mqtt.heartbeat = function() |
||||
local o = { |
||||
nid = _.config.v.nid, |
||||
uptime = tmr.time(), |
||||
heap = node.heap(), |
||||
funcID = _.func.id, |
||||
ip = wifi.sta.getip(), |
||||
ns = _.ns.get() |
||||
} |
||||
_.mqtt.v:publish(_.mqtt.getTopic('heartbeat'), _.package.pack(o), 0, 0); |
||||
end |
||||
_.api.mqtt.ns = function(data) |
||||
local obj = _.package.depack(data); |
||||
_.ns.set(obj); |
||||
end |
||||
_.api.mqtt.func = function(data) |
||||
local obj = _.package.depack(data); |
||||
_.f.write(_.config.v.fs.prefix.system.._.config.v.fs.filename.func, obj); |
||||
_._.restart(); |
||||
end |
||||
_.api.mqtt.restart = function() |
||||
_._.restart(); |
||||
end |
||||
|
||||
|
||||
--Environment Loading & Checking |
||||
---------------------- |
||||
--Flag Checking |
||||
_.flag.load(); |
||||
if _.flag.v == nil then |
||||
_.flag.set(0); |
||||
end |
||||
|
||||
--User Func Checking |
||||
local func = _.f.read(_.config.v.fs.prefix.system.._.config.v.fs.filename.func); |
||||
if func and func.id and func.offline and func.online then |
||||
_.func.id = func.id; |
||||
_.func.offline = func.offline; |
||||
_.func.online = func.online; |
||||
end |
||||
func = nil; |
||||
|
||||
--System Preparation |
||||
-------------------- |
||||
--Signal Start |
||||
_.signal.init(); |
||||
_.signal.set(1500); |
||||
--Decide System Mode |
||||
_.flag.set(_.flag.v + 1); |
||||
if _.flag.v >= _.config.v.flag.MaxRetryTimes and _.flag.v <= _.config.v.flag.MaxRetryTimes + _.config.v.flag.MaxResetTimes then |
||||
_._.reset(); |
||||
elseif _.flag.v > _.config.v.flag.MaxRetryTimes + _.config.v.flag.MaxResetTimes then |
||||
--safe mode |
||||
--Signal set |
||||
_.signal.set(3000); |
||||
do return end; |
||||
end |
||||
|
||||
--OFFLINE System Launch |
||||
----------------------- |
||||
--Signal set |
||||
_.signal.set(800); |
||||
--Run user offline func |
||||
_.flag.ward(function() |
||||
tmr.softwd(_.config.v.func.offline.MaxWaitTime); --start watchdog |
||||
if not __run(_.func.offline, _.timer, _.db.public, nil) then --enable DB and disable MSG |
||||
_._.restart('Offline Func Startup Fail..'); |
||||
end |
||||
tmr.softwd(-1); --disable watchdog |
||||
end); |
||||
|
||||
--Network Modules Init |
||||
---------------------- |
||||
--If OFFLINEONLY is configed, do not start network |
||||
if _.config.v.offlineOnly == true then |
||||
return; |
||||
end |
||||
--Signal set |
||||
_.signal.set(200); |
||||
--Connect to wifi AP |
||||
wifi.setmode(wifi.STATION); |
||||
wifi.sta.sethostname('WIOT-'.._.config.v.nid); |
||||
wifi.sta.config(_.config.v.wifi.config); |
||||
_.timer.setInterval(function(delay) |
||||
if wifi.sta.getip() ~= nil then |
||||
delay(-1); |
||||
_.init.http(); |
||||
_.init.mqtt(); |
||||
end |
||||
end, _.config.v.wifi.CheckInterval); |
||||
|
||||
--http module |
||||
_.init.http = function() |
||||
_.http.v = httpserver.createServer(_.config.v.http.port, function(req, res) |
||||
local path = string.split(req.url, '/'); |
||||
if path[2] == 'discover' then |
||||
_.api.http.discover(res); |
||||
elseif path[2] == 'msg' and path[3] then |
||||
_.api.http.msg(path[3], req, res); |
||||
else |
||||
res.finish('', 500); |
||||
end |
||||
end); |
||||
end |
||||
|
||||
--mqtt module |
||||
_.init.mqtt = function() |
||||
_.mqtt.v = mqtt.Client(_.config.v.nid, _.config.v.mqtt.keepaliveTimer, _.config.v.mqtt.user, _.config.v.mqtt.password); |
||||
_.mqtt.v:lwt(_.mqtt.getTopic('status'), 'offline', 0, 0); |
||||
_.mqtt.v:on('offline', function() |
||||
_.timer.setTimeout(_.mqtt.start, _.config.v.mqtt.OfflineRetryInterval); |
||||
end); |
||||
_.mqtt.v:on('message', function(client, topic, data) |
||||
local path = string.split(string.split(topic, _.config.v.mqtt.topicPrefix), '/'); |
||||
if path[1] == 'ctl' then |
||||
if path[2] == 'heartbeat' then |
||||
_.api.mqtt.heartbeat(); |
||||
elseif path[2] == 'ns' then |
||||
_.api.mqtt.ns(data); |
||||
elseif path[2] == 'func' then |
||||
_.api.mqtt.func(data); |
||||
elseif path[2] == 'restart' then |
||||
_.api.mqtt.restart(); |
||||
end |
||||
elseif path[1] == 'msg' and path[2] then |
||||
_.api.mqtt.msg(path[2], data); |
||||
end |
||||
end); |
||||
end |
||||
|
||||
--ONLINE System Launch |
||||
---------------------- |
||||
--Run user offline func |
||||
_.init.onlineFunc = function() |
||||
_.flag.ward(function() |
||||
tmr.softwd(_.config.v.func.online.MaxWaitTime); --start watchdog |
||||
if not __run(_.func.online, _.timer, _.db.public, _.msg.public) then --enable DB and MSG |
||||
_._.restart('online Func Startup Fail..'); |
||||
end |
||||
tmr.softwd(-1); --disable watchdog |
||||
_.signal.destroy(); --destroy signal |
||||
end); |
||||
end |
||||
|
||||
|
||||
end)(function(func, timer, db, msg) |
||||
return pcall(loadstring(func)); |
||||
end); |
@ -1,314 +0,0 @@ |
||||
tmr.create():alarm(5000, tmr.ALARM_SINGLE, function() |
||||
print('total', node.heap()); |
||||
(function(__run) |
||||
--Packages Used: file, sjson, http, httpserver, mqtt, encoder, timer, node, wifi, gpio |
||||
collectgarbage("collect") |
||||
print('close', node.heap()) |
||||
|
||||
--SYSTEM CONSTANT |
||||
local CONFIG_PATH = 'config.json'; |
||||
local DEFAULT_CONFIG = { |
||||
nid = 'default', |
||||
offlineOnly = true, |
||||
signalPin = 0, |
||||
flag_MaxRetryTimes = 200, |
||||
flag_MaxResetTimes = 3, |
||||
func_offline_MaxWaitTime = 60, |
||||
func_online_MaxWaitTime = 60, |
||||
fs_prefix_root = '', |
||||
fs_prefix_system = '__system/', |
||||
fs_prefix_data = '__data/', |
||||
fs_prefix_swap = '__system/swap/', |
||||
fs_filename_nsmap = 'ns.map', |
||||
fs_filename_flag = 'flag', |
||||
fs_filename_func = 'func.json', |
||||
fs_filename_error = 'error', |
||||
wifi_CheckInterval = 1000, |
||||
wifi_config_ssid = '', |
||||
wifi_config_pwd = '', |
||||
wifi_config_save = false, |
||||
http_port = 6789, |
||||
http_api_discover = '/discover', |
||||
mqtt_host = 'mqtt.yimian.xyz', |
||||
mqtt_port = 1883, |
||||
mqtt_user = nil, |
||||
mqtt_password = nil, |
||||
mqtt_tls = false, |
||||
mqtt_keepaliverTimer = 30, |
||||
mqtt_topicPrefix = '/wiot/default/', |
||||
mqtt_ConnectRetryInterval = 2000, |
||||
mqtt_OfflineRetryInterval = 3000, |
||||
mqtt_PostCheckInterval = 100, |
||||
mqtt_PostTimeout = 10 |
||||
} |
||||
collectgarbage("collect") |
||||
print('SYSTEM CONSTANT', node.heap()) |
||||
|
||||
--Init Global Methods |
||||
--------------------- |
||||
-- File Object Operation |
||||
local fs = { |
||||
read = function(f)--f:filename |
||||
local status, obj = pcall(sjson.decode, file.getcontents(f)); |
||||
if status then |
||||
return obj; |
||||
else |
||||
return {}; |
||||
end |
||||
end, |
||||
write = function(f, obj) |
||||
local status, json = pcall(sjson.encode, obj); |
||||
if status then |
||||
return file.putcontents(f, json); |
||||
else |
||||
return false; |
||||
end |
||||
end |
||||
} |
||||
--split string |
||||
local stringSplit = function(str, reps) |
||||
local resultStrList = {} |
||||
string.gsub(str,'[^'..reps..']+', function (w) |
||||
table.insert(resultStrList,w); |
||||
end); |
||||
return resultStrList; |
||||
end |
||||
|
||||
|
||||
collectgarbage("collect") |
||||
print('Init Global Methods', node.heap()) |
||||
|
||||
|
||||
|
||||
--Config Loading |
||||
----------------- |
||||
--load user config |
||||
config = fs.read(CONFIG_PATH); |
||||
--print sth here, otherwise cause error. Amazing. |
||||
print(''); |
||||
--merge user and default config |
||||
for k, v in pairs(DEFAULT_CONFIG) do |
||||
if config[k] == nil then |
||||
config[k] = v; |
||||
end |
||||
end |
||||
--release resource |
||||
DEFAULT_CONFIG = nil; |
||||
collectgarbage("collect") |
||||
print('Config Loading', node.heap()) |
||||
|
||||
|
||||
--SWAP Medthods |
||||
---------------- |
||||
local swap = { |
||||
set = function(index, val) |
||||
fs.write(config.fs_prefix_swap..index, {val}); |
||||
end, |
||||
get = function(index) |
||||
return fs.read(config.fs_prefix_swap..index)[1]; |
||||
end |
||||
} |
||||
collectgarbage("collect") |
||||
print('SWAP Medthods', node.heap()) |
||||
|
||||
--[[ |
||||
--CONFIG to SWAP |
||||
---------------- |
||||
for k, v in pairs(config) do |
||||
swap.set('C'..k, v); |
||||
end |
||||
config = setmetatable({ |
||||
fs_prefix_swap = config.fs_prefix_swap |
||||
}, { |
||||
__index = function(table, key) |
||||
return swap.get('C'..key); |
||||
end |
||||
}); |
||||
|
||||
collectgarbage("collect") |
||||
print('CONFIG to SWAP', node.heap()) |
||||
]] |
||||
--Variables in SWAP |
||||
---------------- |
||||
var = setmetatable({}, { |
||||
__index = function(table, key) |
||||
return swap.get('V'..key); |
||||
end, |
||||
__newindex = function(table, key, val) |
||||
swap.set('V'..key, val); |
||||
end |
||||
}); |
||||
collectgarbage("collect") |
||||
print('Variables in SWAP', node.heap()) |
||||
|
||||
--Methods in SWAP |
||||
---------------- |
||||
f = setmetatable({}, { |
||||
__index = function(table, key) |
||||
return loadstring(encoder.fromBase64(swap.get('F'..key))); |
||||
end, |
||||
__newindex = function(table, key, val) |
||||
swap.set('F'..key, encoder.toBase64(string.dump(val))); |
||||
end |
||||
}); |
||||
collectgarbage("collect") |
||||
print('Methods in SWAP', node.heap()) |
||||
|
||||
|
||||
--_ |
||||
f._restart = function(err) |
||||
if err then |
||||
file.putcontents(config.fs_prefix_system..config.fs_filename_error, tostring(err)); |
||||
end |
||||
node.restart(); |
||||
end |
||||
f._reset = function() |
||||
file.remove(_.config.v.fs.prefix.system.._.config.v.fs.filename.error); |
||||
file.remove(_.config.v.fs.prefix.system.._.config.v.fs.filename.func); |
||||
file.remove(_.config.v.fs.prefix.system.._.config.v.fs.filename.flag); |
||||
node.restart(); |
||||
end |
||||
|
||||
|
||||
--flag |
||||
f.flag_load = function() |
||||
local flag = file.getcontents(config.fs_prefix_system..config.fs_filename_flag); |
||||
if flag then |
||||
var.flag_v = tonumber(flag); |
||||
end |
||||
end |
||||
f.flag_set = function(val) |
||||
var.flag_v = val; |
||||
file.putcontents(config.fs_prefix_system..config.fs_filename_flag, tostring(val)); |
||||
end |
||||
f.flag_ward = function(func) |
||||
func(); |
||||
f.flag_set(var, config, -1); |
||||
end |
||||
|
||||
--signal |
||||
f.signal_init = function() |
||||
gpio.mode(config.signalPin, gpio.OUTPUT); |
||||
signal_v = tmr.create(); |
||||
end |
||||
f.signal_set = function(interval_ms) |
||||
signal_v:alarm(interval_ms, tmr.ALARM_AUTO, function() |
||||
if gpio.read(config.signalPin) == gpio.HIGH then |
||||
gpio.write(config.signalPin, gpio.LOW); |
||||
else |
||||
gpio.write(config.signalPin, gpio.HIGH); |
||||
end |
||||
end); |
||||
end |
||||
f.signal_destroy = function() |
||||
gpio.write(config.signalPin, gpio.HIGH); |
||||
signal_v:unregister(); |
||||
signal_v = nil; |
||||
end |
||||
|
||||
--timer |
||||
f.timer_setTimeout = function(func, time_ms) |
||||
return tmr.create():alarm(time_ms, tmr.ALARM_SINGLE, func); |
||||
end |
||||
|
||||
f.timer_setInterval = function(func, time_ms) |
||||
return tmr.create():alarm(time_ms, tmr.ALARM_AUTO, func); |
||||
end |
||||
|
||||
--mqtt |
||||
f.mqtt_getTopic = function(s) |
||||
return _.config.v.mqtt.topicPrefix.._.config.v.nid..'/'..s; |
||||
end |
||||
f.mqtt_start = function() |
||||
mqtt_v:connect( |
||||
config.mqtt_host, |
||||
config.mqtt_port, |
||||
config.mqtt_tls, |
||||
function(client) |
||||
client:subscribe(f.mqtt_getTopic('msg/#')); |
||||
client:subscribe(f.mqtt_getTopic('ctl/#')); |
||||
client:publish(f.mqtt_getTopic('status'), 'online', 0, 0); |
||||
end, |
||||
function(client, reason) |
||||
f.timer_setTimeout(f.mqtt_start, config.mqtt_ConnectRetryInterval); |
||||
end |
||||
); |
||||
end |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
collectgarbage("collect") |
||||
print('Methods in SWAP', node.heap()) |
||||
|
||||
|
||||
|
||||
|
||||
--Environment Loading & Checking |
||||
---------------------- |
||||
--Flag Checking |
||||
f.flag_load(); |
||||
if var.flag_v == nil then |
||||
f.flag_set(0); |
||||
end |
||||
--User Func Checking |
||||
local func = fs.read(config.fs_prefix_system..config.fs_filename_func); |
||||
if func and func.id and func.offline and func.online then |
||||
var.func_id = func.id; |
||||
var.func_offline = func.offline; |
||||
var.func_online = func.online; |
||||
end |
||||
func = nil; |
||||
|
||||
collectgarbage("collect") |
||||
print('Environment Loading & Checking', node.heap()) |
||||
|
||||
|
||||
--System Preparation |
||||
-------------------- |
||||
--Signal Start |
||||
f.signal_init(); |
||||
collectgarbage("collect") |
||||
print('System Preparation', node.heap()) |
||||
f.signal_set(1500); |
||||
collectgarbage("collect") |
||||
print('System Preparation', node.heap()) |
||||
--Decide System Mode |
||||
f.flag_set(var.flag_v + 1); |
||||
collectgarbage("collect") |
||||
print('System Preparation', node.heap()) |
||||
if var.flag_v >= config.flag_MaxRetryTimes and var.flag_v <= config.flag_MaxRetryTimes + config.flag_MaxResetTimes then |
||||
f._reset(); |
||||
elseif var.flag_v > config.flag_MaxRetryTimes + config.flag_MaxResetTimes then |
||||
--safe mode |
||||
--Signal set |
||||
f.signal_set(3000); |
||||
do return end; |
||||
end |
||||
|
||||
collectgarbage("collect") |
||||
print('System Preparation', node.heap()) |
||||
|
||||
|
||||
|
||||
--OFFLINE System Launch |
||||
----------------------- |
||||
--Signal set |
||||
f.signal_set(800); |
||||
--Run user offline func |
||||
f.flag_ward(function() |
||||
tmr.softwd(config.func_offline_MaxWaitTime); --start watchdog |
||||
if not __run(var.func_offline) then --enable DB and disable MSG |
||||
f._restart('Offline Func Startup Fail..'); |
||||
end |
||||
tmr.softwd(-1); --disable watchdog |
||||
end); |
||||
collectgarbage("collect") |
||||
print('OFFLINE System Launch', node.heap()) |
||||
|
||||
|
||||
end)(function(func) |
||||
return pcall(loadstring(func)); |
||||
end); |
||||
end); |
Binary file not shown.
@ -1,120 +0,0 @@ |
||||
--CONFIG |
||||
CONFIG = { |
||||
firmware = { |
||||
version = '0.0.1' |
||||
}, |
||||
wifi = { |
||||
station = { |
||||
ssid = "yimian-iot", |
||||
pwd = "1234567890.", |
||||
save = true |
||||
} |
||||
}, |
||||
coap = { |
||||
server = { |
||||
port = 5683 |
||||
} |
||||
}, |
||||
w = { |
||||
id = {} |
||||
director = { |
||||
ip = '192.168.3.251' |
||||
}, |
||||
heartbeat = { |
||||
interval = 15000 |
||||
} |
||||
} |
||||
} |
||||
|
||||
--Global Var |
||||
cs = nil --coAP Server |
||||
cc = nil --coAP Client |
||||
|
||||
--wIoT Toolbox |
||||
w = { |
||||
f = {}, |
||||
push = function(hash, s) |
||||
w.f[hash] = loadstring(s) |
||||
cs:func('w.f.'..hash) |
||||
return hash |
||||
end, |
||||
pull = function(hash) |
||||
w.f[hash] = nil |
||||
w.refresh() |
||||
end, |
||||
clear = function() |
||||
w.f = nil |
||||
w.refresh() |
||||
end, |
||||
start = function() |
||||
cs = coap.Server() |
||||
cs:listen(CONFIG.coap.server.port) |
||||
w.push('_/info', 'function() local status, json;ok, json = pcall(sjson.encode, CONFIG);return json;end') |
||||
w.push('_/w/f', 'function() local status, json;ok, json = pcall(sjson.encode, w.f);return json;end'); |
||||
w.push('_/w/push', 'function() ') |
||||
end, |
||||
stop = function() |
||||
cs:close() |
||||
cs = nil |
||||
collectgarbage("collect") |
||||
end, |
||||
refresh = function() |
||||
w.stop() |
||||
w.start() |
||||
for k, v in pairs(w.f) do |
||||
cs:func('w.f.'..k) |
||||
end |
||||
end |
||||
} |
||||
|
||||
--Functions |
||||
func = { |
||||
init = { |
||||
run = function() |
||||
func.init.wifi(func.init.coap, func.init.w, func.run) |
||||
end, |
||||
wifi = function(after, after2, after3) |
||||
print('Setting up WIFI...') |
||||
wifi.setmode(wifi.STATION) |
||||
wifi.sta.config(CONFIG.wifi.station) |
||||
wifi.sta.connect() |
||||
local wifiInit = tmr.create() |
||||
wifiInit:register(1000, tmr.ALARM_AUTO, function() |
||||
if wifi.sta.getip() == nil then |
||||
print('Waiting for IP ...') |
||||
else |
||||
print('IP is ' .. wifi.sta.getip()) |
||||
wifiInit:unregister() |
||||
after(after2, after3) |
||||
end |
||||
end) |
||||
wifiInit:start() |
||||
end, |
||||
coap = function (after, after2) |
||||
cs = coap.Server() |
||||
cs:listen(CONFIG.coap.server.port) |
||||
cc = coap.Client() |
||||
after(after2) |
||||
end, |
||||
w = function(after) |
||||
|
||||
if after then after() |
||||
end |
||||
}, |
||||
randomLetter = function(len) |
||||
local rt = "" |
||||
for i = 1, len, 1 do |
||||
rt = rt..string.char(math.random(97,122)) |
||||
end |
||||
return rt |
||||
end |
||||
|
||||
} |
||||
|
||||
--Run |
||||
func.run = function() |
||||
gpio.write(0, gpio.LOW) |
||||
end |
||||
|
||||
--exec Init |
||||
func.init.run() |
Binary file not shown.
@ -1,15 +0,0 @@ |
||||
var packageRoot = require.resolve('nodemcu-tool') |
||||
.match(/^.*[\/\\]node_modules[\/\\][^\/\\]*/)[0]; |
||||
|
||||
console.log(packageRoot) |
||||
|
||||
|
||||
;(async ()=>{ |
||||
var _connector = require('nodemcu-tool'); |
||||
console.log(await _connector.connect('COM3')) |
||||
console.log('dd') |
||||
console.log(await _connector.upload('test/led.lua', 'led.lua.', {minify: true}, ()=>{})) |
||||
await _connector.disconnect(); |
||||
})(); |
||||
|
||||
//
|
Loading…
Reference in new issue