mirror of https://github.com/iotcat/wIoT
parent
b1d4811c6b
commit
830b23418a
13 changed files with 1835 additions and 693 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,31 +1,15 @@ |
||||
{ |
||||
"firmware": { |
||||
"version": "0.0.1" |
||||
}, |
||||
"nid": "good", |
||||
"wifi": { |
||||
"station": { |
||||
"ssid": "yimian-iot", |
||||
"pwd": "1234567890.", |
||||
"save": true |
||||
} |
||||
"ssid": "yimian-iot", |
||||
"pwd": "1234567890." |
||||
}, |
||||
"udp": { |
||||
"server": { |
||||
"port": 5678 |
||||
} |
||||
"msg": { |
||||
"port": 6789 |
||||
}, |
||||
"w": { |
||||
"id": "test2", |
||||
"director": { |
||||
"ip": "192.168.3.100", |
||||
"port": 5678 |
||||
}, |
||||
"heartbeat": { |
||||
"interval": 2000 |
||||
}, |
||||
"key": "1234567890abcdef", |
||||
"scanInterval": 300, |
||||
"retryInterval": 10000, |
||||
"maxRetryTimes": 5 |
||||
"director": { |
||||
"HeartbeatInterval": 10000, |
||||
"ip": "192.168.3.100", |
||||
"port": 4444 |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,134 @@ |
||||
-- 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 } |
Binary file not shown.
@ -0,0 +1,217 @@ |
||||
------------------------------------------------------------------------------ |
||||
-- 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.
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,842 @@ |
||||
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); |
@ -0,0 +1,314 @@ |
||||
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.
Loading…
Reference in new issue