luaOTA updated to include object form timers (#2752)
This commit is contained in:
parent
f1b5dfc34e
commit
45a7187a6c
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"files": [ "main.lc", "supporfile.lc", "othercontent.txt" ],
|
||||
"secret": "supersekrit"
|
||||
}
|
|
@ -31,7 +31,7 @@ call which invokes the `luaOTA` module by a `require "luaOTA.check"` statement.
|
|||
|
||||
The `config.json` file which provides the minimum configuration parameters to connect to
|
||||
the WiFi and provisioning server, however these can by overridden through the UART by
|
||||
first doing a `tmr.stop(0)` and then a manual initialisation as described in the
|
||||
first doing a `abortOTA()` and then a manual initialisation as described in the
|
||||
[init.lua](#initlua) section below.
|
||||
|
||||
`luaOTA` configures the wifi and connects to the required sid in STA mode using the
|
||||
|
@ -90,13 +90,17 @@ require "LuaOTA.check"
|
|||
however if the configuration is incomplete then this can be aborted as manual process
|
||||
by entering the manual command through the UART
|
||||
```Lua
|
||||
tmr.stop(0); require "luaOTA.check":_init {ssid ="SOMESID" --[[etc. ]]}
|
||||
abortOTA(); require "luaOTA.check":_init {ssid ="SOMESID" --[[etc. ]]}
|
||||
```
|
||||
where the parameters to the `_init` method are:
|
||||
|
||||
- `ssid` and `spwd`. The SSID of the Wifi service to connect to, together with its
|
||||
password.
|
||||
- `server` and `port`. The name or IP address and port of the provisioning server.
|
||||
- `app`. The filename of the module which will be `required` after provisioning is
|
||||
complete. Defaults to LuaOTA/default.
|
||||
- `entry`. The method that will be called on the module indicated by `app`. Defaults
|
||||
to `init`
|
||||
- `secret`. A site-specific secret shared with the provisioning server for MD5-based
|
||||
signing of the protocol messages.
|
||||
- `leave`. If true the STA service is left connected otherwise the wifi is shutdown
|
||||
|
@ -129,6 +133,12 @@ Note that even though this file is included in the `luaOTA` subdirectory within
|
|||
examples, this is designed to run on the host and should not be included in the
|
||||
ESP SPIFFS.
|
||||
|
||||
The example server expects a repository directory, which is expected to contain
|
||||
the to-be-provisioned files (.lua files, .lc files...). Additionally, it expects
|
||||
a .json file for every ESP that is to be provisioned, containing the "secret"
|
||||
as well as the relevant filenames. This file should be called 'ESP-xxxxxxxx.json',
|
||||
with 'xxxxxxxx' replaced with the ChipID.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The NodeMCu build must include the following modules: `wifi`, `net`, `file`, `tmr`,
|
||||
|
@ -156,11 +166,6 @@ called using the object form self:someFunc() to get the context as a parameter.
|
|||
- This coding also makes a lot of use of tailcalls (See PiL 6.3) to keep the stack size
|
||||
to a minimum.
|
||||
|
||||
- The update process uses a master timer in `tmr` slot 0. The index form is used here
|
||||
in preference to the object form because of the reduced memory footprint. This also
|
||||
allows the developer to abort the process early in the boot sequence by issuing a
|
||||
`tmr.stop(0)` through UART0.
|
||||
|
||||
- The command protocol is unencrypted and uses JSON encoding, but all exchanges are
|
||||
signed by a 6 char signature taken extracted from a MD5 based digest across the JSON
|
||||
string. Any command which fails the signature causes the update to be aborted. Commands
|
||||
|
@ -205,7 +210,7 @@ function using an object constructor `self:self:somefunction()`, but where the f
|
|||
can have a self argument then the alternative is to use an upvalue binding. See the
|
||||
`tmr` alarm call at the end of `_init.lua` as an example:
|
||||
```Lua
|
||||
tmr.alarm(0, 500, tmr.ALARM_AUTO, self:_doTick())
|
||||
self.timer:alarm( 500, tmr.ALARM_AUTO, self:_doTick())
|
||||
```
|
||||
- The `self:_doTick()` is evaluated before the alarm API call. This autoloads
|
||||
`luaOTA/_doTick.lc` which stores `self` as a local and returns a function which takes
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
tmr.stop(0)--SAFETRIM
|
||||
if (self.timer) then self.timer:stop() end--SAFETRIM
|
||||
-- function _doTick(self)
|
||||
|
||||
-- Upvals
|
||||
|
@ -32,7 +32,7 @@ tmr.stop(0)--SAFETRIM
|
|||
-- some resources that are no longer needed and set backstop timer for general
|
||||
-- timeout. This also dereferences the previous doTick cb so it can now be GCed.
|
||||
collectgarbage()
|
||||
tmr.alarm(0, 30000, tmr.ALARM_SINGLE, self.startApp)
|
||||
self.timer:alarm(0, 30000, tmr.ALARM_SINGLE, self.startApp)
|
||||
return self:_provision(socket,rec)
|
||||
end
|
||||
|
||||
|
@ -67,7 +67,7 @@ tmr.stop(0)--SAFETRIM
|
|||
return self.startApp("OK: Timeout on waiting for wifi station setup")
|
||||
|
||||
elseif (tick_count == 26) then -- wait up to 2.5 secs for TCP response
|
||||
tmr.unregister(0)
|
||||
self.timer:unregister()
|
||||
pcall(conn.close, conn)
|
||||
self.socket=nil
|
||||
return startApp("OK: Timeout on waiting for provision service response")
|
||||
|
|
|
@ -45,5 +45,5 @@
|
|||
|
||||
package.loaded[self.modname] = nil
|
||||
self.modname=nil
|
||||
tmr.alarm(0, 500, tmr.ALARM_AUTO, self:_doTick())
|
||||
self.timer:alarm( 500, tmr.ALARM_AUTO, self:_doTick())
|
||||
-- end
|
||||
|
|
|
@ -17,7 +17,7 @@ local function receiveRec(socket, rec) -- upval: self, buf, crypto
|
|||
-- Note that for 2nd and subsequent responses, we assme that the service has
|
||||
-- "authenticated" itself, so any protocol errors are fatal and lkely to
|
||||
-- cause a repeating boot, throw any protocol errors are thrown.
|
||||
local buf, config, file, log = buf, self.config, file, self.log
|
||||
local config, file, log = self.config, file, self.log
|
||||
local cmdlen = (rec:find('\n',1, true) or 0) - 1
|
||||
local cmd,hash = rec:sub(1,cmdlen-6), rec:sub(cmdlen-5,cmdlen)
|
||||
if cmdlen < 16 or
|
||||
|
@ -89,9 +89,9 @@ local function receiveRec(socket, rec) -- upval: self, buf, crypto
|
|||
end
|
||||
|
||||
if s then
|
||||
print("Updated ".. name)
|
||||
print("Updated ".. cmd.name)
|
||||
else
|
||||
file.remove(name)
|
||||
file.remove(cmd.name)
|
||||
resp.s = "write failed"
|
||||
end
|
||||
buf = {}
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
--------------------------------------------------------------------------------
|
||||
|
||||
-- upvals
|
||||
local crypto, file, json, net, node, table, tmr, wifi =
|
||||
crypto, file, sjson, net, node, table, tmr, wifi
|
||||
local crypto, file, json, net, node, table, wifi =
|
||||
crypto, file, sjson, net, node, table, wifi
|
||||
local error, pcall = error, pcall
|
||||
local loadfile, gc = loadfile, collectgarbage
|
||||
local concat, unpack = table.concat, unpack or table.unpack
|
||||
|
@ -19,7 +19,11 @@ local self = {post = node.task.post, prefix = "luaOTA/", conf = {}}
|
|||
|
||||
self.log = (DEBUG == true) and print or function() end
|
||||
self.modname = ...
|
||||
self.timer = tmr.create()
|
||||
|
||||
_G["stopOTA"] = function()
|
||||
self.timer:stop()
|
||||
end
|
||||
--------------------------------------------------------------------------------------
|
||||
-- Utility Functions
|
||||
|
||||
|
@ -40,9 +44,9 @@ function self.sign(arg) --upval: crypto, json, self
|
|||
return arg .. crypto.toHex(crypto.hmac("MD5", arg, self.secret):sub(-3)) .. '\n'
|
||||
end
|
||||
|
||||
function self.startApp(arg) --upval: gc, self, tmr, wifi
|
||||
function self.startApp(arg) --upval: gc, self, wifi
|
||||
gc();gc()
|
||||
tmr.unregister(0)
|
||||
self.timer.unregister()
|
||||
self.socket = nil
|
||||
if not self.config.leave then wifi.setmode(wifi.NULLMODE,false) end
|
||||
local appMod = self.config.app or "luaOTA.default"
|
||||
|
|
Loading…
Reference in New Issue