Commit 6926c66b authored by galjonsfigur's avatar galjonsfigur Committed by Marcel Stör
Browse files

Polish Lua examples (#2846)

* Add missing globals from luacheck config

* Fix luacheck warnings in all lua files

* Re-enable luacheck in Travis

* Speed up Travis by using preinstalled LuaRocks

* Fix more luacheck warnings in httpserver lua module

* Fix DCC module and add appropriate definitions to luacheck config.

* Change inline comments from ignoring block to only ignore specific line

* Add Luacheck for Windows and enable it for both Windows and Linux

* Change luacheck exceptions and fix errors from 1st round of polishing

* Add retry and timeout params to wget
parent 36df8d00
...@@ -20,6 +20,7 @@ addons: ...@@ -20,6 +20,7 @@ addons:
packages: packages:
- python-serial - python-serial
- srecord - srecord
- luarocks
cache: cache:
- directories: - directories:
- cache - cache
...@@ -33,4 +34,5 @@ script: ...@@ -33,4 +34,5 @@ script:
- echo "checking:" - echo "checking:"
- find lua_modules lua_examples -iname "*.lua" -print0 | xargs -0 echo - find lua_modules lua_examples -iname "*.lua" -print0 | xargs -0 echo
- find lua_modules lua_examples -iname "*.lua" -print0 | xargs -0 $LUACC -p - find lua_modules lua_examples -iname "*.lua" -print0 | xargs -0 $LUACC -p
# - if [ "$OS" = "linux" ]; then bash "$TRAVIS_BUILD_DIR"/tools/travis/run-luacheck.sh || true ; fi - if [ "$OS" = "linux" ]; then bash "$TRAVIS_BUILD_DIR"/tools/travis/run-luacheck-linux.sh; fi
- if [ "$OS" = "windows" ]; then bash "$TRAVIS_BUILD_DIR"/tools/travis/run-luacheck-windows.sh; fi
-- --
-- Light sensor on ADC(0), RGB LED connected to gpio12(6) Green, gpio13(7) Blue & gpio15(8) Red. -- Light sensor on adc0(A0), RGB LED connected to gpio12(D6) Green, gpio13(D7) Blue & gpio15(D8) Red.
-- This works out of the box on the typical ESP8266 evaluation boards with Battery Holder -- This works out of the box on the typical ESP8266 evaluation boards with Battery Holder
-- --
-- It uses the input from the sensor to drive a "rainbow" effect on the RGB LED -- It uses the input from the sensor to drive a "rainbow" effect on the RGB LED
-- Includes a very "pseudoSin" function -- Includes a very "pseudoSin" function
-- --
-- Required C Modules: adc, tmr, pwm
function led(r,Sg,b) local redLed, greenLed, blueLed = 8, 6, 7
pwm.setduty(8,r)
pwm.setduty(6,g) local function setRGB(r,g,b)
pwm.setduty(7,b) pwm.setduty(redLed, r)
pwm.setduty(greenLed, g)
pwm.setduty(blueLed, b)
end end
-- this is perhaps the lightest weight sin function in existance -- this is perhaps the lightest weight sin function in existence
-- Given an integer from 0..128, 0..512 appximating 256 + 256 * sin(idx*Pi/256) -- Given an integer from 0..128, 0..512 approximating 256 + 256 * sin(idx*Pi/256)
-- This is first order square approximation of sin, it's accurate around 0 and any multiple of 128 (Pi/2), -- This is first order square approximation of sin, it's accurate around 0 and any multiple of 128 (Pi/2),
-- 92% accurate at 64 (Pi/4). -- 92% accurate at 64 (Pi/4).
function pseudoSin (idx) local function pseudoSin(idx)
idx = idx % 128 idx = idx % 128
lookUp = 32 - idx % 64 local lookUp = 32 - idx % 64
val = 256 - (lookUp * lookUp) / 4 local val = 256 - (lookUp * lookUp) / 4
if (idx > 64) then if (idx > 64) then
val = - val; val = - val;
end end
return 256+val return 256+val
end end
pwm.setup(6,500,512) do
pwm.setup(7,500,512) pwm.setup(redLed, 500, 512)
pwm.setup(8,500,512) pwm.setup(greenLed,500, 512)
pwm.start(6) pwm.setup(blueLed, 500, 512)
pwm.start(7) pwm.start(redLed)
pwm.start(8) pwm.start(greenLed)
pwm.start(blueLed)
tmr.alarm(1,20,1,function() tmr.create():alarm(20, tmr.ALARM_AUTO, function()
idx = 3 * adc.read(0) / 2 local idx = 3 * adc.read(0) / 2
r = pseudoSin(idx) local r = pseudoSin(idx)
g = pseudoSin(idx + 43) local g = pseudoSin(idx + 43) -- ~1/3rd of 128
b = pseudoSin(idx + 85) local b = pseudoSin(idx + 85) -- ~2/3rd of 128
led(r,g,b) setRGB(r,g,b)
idx = (idx + 1) % 128 end)
end) end
...@@ -4,7 +4,7 @@ local PIN = 2 -- GPIO4 ...@@ -4,7 +4,7 @@ local PIN = 2 -- GPIO4
local addr = 0x12a local addr = 0x12a
CV = {[29]=0, local CV = {[29]=0,
[1]=bit.band(addr, 0x3f), --CV_ACCESSORY_DECODER_ADDRESS_LSB (6 bits) [1]=bit.band(addr, 0x3f), --CV_ACCESSORY_DECODER_ADDRESS_LSB (6 bits)
[9]=bit.band(bit.rshift(addr,6), 0x7) --CV_ACCESSORY_DECODER_ADDRESS_MSB (3 bits) [9]=bit.band(bit.rshift(addr,6), 0x7) --CV_ACCESSORY_DECODER_ADDRESS_MSB (3 bits)
} }
...@@ -37,18 +37,18 @@ end ...@@ -37,18 +37,18 @@ end
local function DCC_command(cmd, params) local function DCC_command(cmd, params)
if not is_new(cmd, params) then return end if not is_new(cmd, params) then return end
if cmd == dcc.DCC_IDLE then if cmd == dcc.DCC_IDLE then
return return
elseif cmd == dcc.DCC_TURNOUT then elseif cmd == dcc.DCC_TURNOUT then
print("Turnout command") print("Turnout command")
elseif cmd == dcc.DCC_SPEED then elseif cmd == dcc.DCC_SPEED then
print("Speed command") print("Speed command")
elseif cmd == dcc.DCC_FUNC then elseif cmd == dcc.DCC_FUNC then
print("Function command") print("Function command")
else else
print("Other command", cmd) print("Other command", cmd)
end end
for i,j in pairs(params) do for i,j in pairs(params) do
print(i, j) print(i, j)
end end
...@@ -69,18 +69,21 @@ local function CV_callback(operation, param) ...@@ -69,18 +69,21 @@ local function CV_callback(operation, param)
elseif operation == dcc.CV_VALID then elseif operation == dcc.CV_VALID then
oper = "Valid" oper = "Valid"
result = 1 result = 1
elseif operation == CV_RESET then elseif operation == dcc.CV_RESET then
oper = "Reset" oper = "Reset"
CV = {} CV = {}
end end
print(("[CV_callback] %s CV %d%s"):format(oper, param.CV, param.Value and "\tValue: "..param.Value or "\tValue: nil")) print(("[CV_callback] %s CV %d%s")
:format(oper, param.CV, param.Value and "\tValue: "..param.Value or "\tValue: nil"))
return result return result
end end
dcc.setup(PIN, dcc.setup(PIN,
DCC_command, DCC_command,
dcc.MAN_ID_DIY, 1, dcc.MAN_ID_DIY, 1,
--bit.bor(dcc.FLAGS_AUTO_FACTORY_DEFAULT, dcc.FLAGS_DCC_ACCESSORY_DECODER, dcc.FLAGS_MY_ADDRESS_ONLY), -- Accessories (turnouts) decoder -- Accessories (turnouts) decoder:
bit.bor(dcc.FLAGS_AUTO_FACTORY_DEFAULT), -- Cab (train) decoder --bit.bor(dcc.FLAGS_AUTO_FACTORY_DEFAULT, dcc.FLAGS_DCC_ACCESSORY_DECODER, dcc.FLAGS_MY_ADDRESS_ONLY),
-- Cab (train) decoder
bit.bor(dcc.FLAGS_AUTO_FACTORY_DEFAULT),
0, -- ??? 0, -- ???
CV_callback) CV_callback)
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
-- was tested with an AOL and Time Warner cable email accounts (GMail and other services who do -- was tested with an AOL and Time Warner cable email accounts (GMail and other services who do
-- not support no SSL access will not work). -- not support no SSL access will not work).
require("imap") local imap = require("imap")
local IMAP_USERNAME = "email@domain.com" local IMAP_USERNAME = "email@domain.com"
local IMAP_PASSWORD = "password" local IMAP_PASSWORD = "password"
...@@ -25,21 +25,13 @@ local SSID_PASSWORD = "password" ...@@ -25,21 +25,13 @@ local SSID_PASSWORD = "password"
local count = 0 -- we will send several IMAP commands/requests, this variable helps keep track of which one to send local count = 0 -- we will send several IMAP commands/requests, this variable helps keep track of which one to send
local imap_socket, timer
-- configure the ESP8266 as a station
wifi.setmode(wifi.STATION)
wifi.sta.config(SSID,SSID_PASSWORD)
wifi.sta.autoconnect(1)
-- create an unencrypted connection
local imap_socket = net.createConnection(net.TCP,0)
--- ---
-- @name setup -- @name setup
-- @description A call back function used to begin reading email -- @description A call back function used to begin reading email
-- upon sucessfull connection to the IMAP server -- upon sucessfull connection to the IMAP server
function setup(sck) local function setup(sck)
-- Set the email user name and password, IMAP tag, and if debugging output is needed -- Set the email user name and password, IMAP tag, and if debugging output is needed
imap.config(IMAP_USERNAME, imap.config(IMAP_USERNAME,
IMAP_PASSWORD, IMAP_PASSWORD,
...@@ -49,19 +41,16 @@ function setup(sck) ...@@ -49,19 +41,16 @@ function setup(sck)
imap.login(sck) imap.login(sck)
end end
imap_socket:on("connection",setup) -- call setup() upon connection
imap_socket:connect(IMAP_PORT,IMAP_SERVER) -- connect to the IMAP server
local subject = "" local subject = ""
local from = "" local from = ""
local message = "" local body = ""
--- ---
-- @name do_next -- @name do_next
-- @description A call back function for a timer alarm used to check if the previous -- @description A call back function for a timer alarm used to check if the previous
-- IMAP command reply has been processed. If the IMAP reply has been processed -- IMAP command reply has been processed. If the IMAP reply has been processed
-- this function will call the next IMAP command function necessary to read the email -- this function will call the next IMAP command function necessary to read the email
function do_next() local function do_next()
-- Check if the IMAP reply was processed -- Check if the IMAP reply was processed
if(imap.response_processed() == true) then if(imap.response_processed() == true) then
...@@ -75,15 +64,18 @@ function do_next() ...@@ -75,15 +64,18 @@ function do_next()
count = count + 1 count = count + 1
elseif (count == 1) then elseif (count == 1) then
-- After examining/selecting the INBOX folder we can begin to retrieve emails. -- After examining/selecting the INBOX folder we can begin to retrieve emails.
imap.fetch_header(imap_socket,imap.get_most_recent_num(),"SUBJECT") -- Retrieve the SUBJECT of the first/newest email -- Retrieve the SUBJECT of the first/newest email
imap.fetch_header(imap_socket,imap.get_most_recent_num(),"SUBJECT")
count = count + 1 count = count + 1
elseif (count == 2) then elseif (count == 2) then
subject = imap.get_header() -- store the SUBJECT response in subject subject = imap.get_header() -- store the SUBJECT response in subject
imap.fetch_header(imap_socket,imap.get_most_recent_num(),"FROM") -- Retrieve the FROM of the first/newest email -- Retrieve the FROM of the first/newest email
imap.fetch_header(imap_socket,imap.get_most_recent_num(),"FROM")
count = count + 1 count = count + 1
elseif (count == 3) then elseif (count == 3) then
from = imap.get_header() -- store the FROM response in from from = imap.get_header() -- store the FROM response in from
imap.fetch_body_plain_text(imap_socket,imap.get_most_recent_num()) -- Retrieve the BODY of the first/newest email -- Retrieve the BODY of the first/newest email
imap.fetch_body_plain_text(imap_socket,imap.get_most_recent_num())
count = count + 1 count = count + 1
elseif (count == 4) then elseif (count == 4) then
body = imap.get_body() -- store the BODY response in body body = imap.get_body() -- store the BODY response in body
...@@ -92,9 +84,9 @@ function do_next() ...@@ -92,9 +84,9 @@ function do_next()
else else
-- display the email contents -- display the email contents
-- create patterns to strip away IMAP protocl text from actual message -- create patterns to strip away IMAP protocol text from actual message
pattern1 = "(\*.+\}\r\n)" -- to remove "* n command (BODY[n] {n}" local pattern1 = "%*.*}\n" -- to remove "* n command (BODY[n] {n}"
pattern2 = "(%)\r\n.+)" -- to remove ") t1 OK command completed" local pattern2 = "%)\n.+" -- to remove ") t1 OK command completed"
from = string.gsub(from,pattern1,"") from = string.gsub(from,pattern1,"")
from = string.gsub(from,pattern2,"") from = string.gsub(from,pattern2,"")
...@@ -108,7 +100,7 @@ function do_next() ...@@ -108,7 +100,7 @@ function do_next()
body = string.gsub(body,pattern2,"") body = string.gsub(body,pattern2,"")
print("Message: " .. body) print("Message: " .. body)
tmr.stop(0) -- Stop the timer alarm timer:stop() -- Stop the timer alarm
imap_socket:close() -- close the IMAP socket imap_socket:close() -- close the IMAP socket
collectgarbage() -- clean up collectgarbage() -- clean up
end end
...@@ -116,5 +108,18 @@ function do_next() ...@@ -116,5 +108,18 @@ function do_next()
end end
-- A timer alarm is sued to check if an IMAP reply has been processed do
tmr.alarm(0,1000,1, do_next) -- configure the ESP8266 as a station
wifi.setmode(wifi.STATION)
wifi.sta.config(SSID,SSID_PASSWORD)
wifi.sta.autoconnect(1)
-- create an unencrypted connection
imap_socket = net.createConnection(net.TCP,0)
imap_socket:on("connection",setup) -- call setup() upon connection
imap_socket:connect(IMAP_PORT,IMAP_SERVER) -- connect to the IMAP server
-- A timer alarm is sued to check if an IMAP reply has been processed
timer = tmr.create()
timer:alarm(1000, tmr.ALARM_AUTO, do_next)
end
--- ---
-- Working Example: https://www.youtube.com/watch?v=CcRbFIJ8aeU -- Working Example: https://www.youtube.com/watch?v=CcRbFIJ8aeU
-- @description a basic SMTP email example. You must use an account which can provide unencrypted authenticated access. -- @description a basic SMTP email example. You must use an account which can
-- This example was tested with an AOL and Time Warner email accounts. GMail does not offer unecrypted authenticated access. -- provide unencrypted authenticated access.
-- This example was tested with an AOL and Time Warner email accounts.
-- GMail does not offer unencrypted authenticated access.
-- To obtain your email's SMTP server and port simply Google it e.g. [my email domain] SMTP settings -- To obtain your email's SMTP server and port simply Google it e.g. [my email domain] SMTP settings
-- For example for timewarner you'll get to this page http://www.timewarnercable.com/en/support/faqs/faqs-internet/e-mailacco/incoming-outgoing-server-addresses.html -- For example for timewarner you'll get to this page
-- http://www.timewarnercable.com/en/support/faqs/faqs-internet/e-mailacco/incoming-outgoing-server-addresses.html
-- To Learn more about SMTP email visit: -- To Learn more about SMTP email visit:
-- SMTP Commands Reference - http://www.samlogic.net/articles/smtp-commands-reference.htm -- SMTP Commands Reference - http://www.samlogic.net/articles/smtp-commands-reference.htm
-- See "SMTP transport example" in this page http://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol -- See "SMTP transport example" in this page http://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol
-- @author Miguel -- @author Miguel
require("base64")
-- The email and password from the account you want to send emails from -- The email and password from the account you want to send emails from
local MY_EMAIL = "esp8266@domain.com" local MY_EMAIL = "esp8266@domain.com"
local EMAIL_PASSWORD = "123456" local EMAIL_PASSWORD = "123456"
...@@ -37,18 +38,18 @@ wifi.sta.autoconnect(1) ...@@ -37,18 +38,18 @@ wifi.sta.autoconnect(1)
local email_subject = "" local email_subject = ""
local email_body = "" local email_body = ""
local count = 0 local count = 0
local timer
local smtp_socket = nil -- will be used as socket to email server local smtp_socket = nil -- will be used as socket to email server
-- The display() function will be used to print the SMTP server's response -- The display() function will be used to print the SMTP server's response
function display(sck,response) local function display(sck, response) -- luacheck: no unused
print(response) print(response)
end end
-- The do_next() function is used to send the SMTP commands to the SMTP server in the required sequence. -- The do_next() function is used to send the SMTP commands to the SMTP server in the required sequence.
-- I was going to use socket callbacks but the code would not run callbacks after the first 3. -- I was going to use socket callbacks but the code would not run callbacks after the first 3.
function do_next() local function do_next()
if(count == 0)then if(count == 0)then
count = count+1 count = count+1
local IP_ADDRESS = wifi.sta.getip() local IP_ADDRESS = wifi.sta.getip()
...@@ -58,10 +59,10 @@ function do_next() ...@@ -58,10 +59,10 @@ function do_next()
smtp_socket:send("AUTH LOGIN\r\n") smtp_socket:send("AUTH LOGIN\r\n")
elseif(count == 2) then elseif(count == 2) then
count = count + 1 count = count + 1
smtp_socket:send(base64.enc(MY_EMAIL).."\r\n") smtp_socket:send(encoder.toBase64(MY_EMAIL).."\r\n")
elseif(count == 3) then elseif(count == 3) then
count = count + 1 count = count + 1
smtp_socket:send(base64.enc(EMAIL_PASSWORD).."\r\n") smtp_socket:send(encoder.toBase64(EMAIL_PASSWORD).."\r\n")
elseif(count==4) then elseif(count==4) then
count = count+1 count = count+1
smtp_socket:send("MAIL FROM:<" .. MY_EMAIL .. ">\r\n") smtp_socket:send("MAIL FROM:<" .. MY_EMAIL .. ">\r\n")
...@@ -82,26 +83,27 @@ function do_next() ...@@ -82,26 +83,27 @@ function do_next()
smtp_socket:send(message.."\r\n.\r\n") smtp_socket:send(message.."\r\n.\r\n")
elseif(count==8) then elseif(count==8) then
count = count+1 count = count+1
tmr.stop(0) timer:stop()
smtp_socket:send("QUIT\r\n") smtp_socket:send("QUIT\r\n")
else else
smtp_socket:close() smtp_socket:close()
end end
end end
-- The connectted() function is executed when the SMTP socket is connected to the SMTP server. -- The connected() function is executed when the SMTP socket is connected to the SMTP server.
-- This function will create a timer to call the do_next function which will send the SMTP commands -- This function will create a timer to call the do_next function which will send the SMTP commands
-- in sequence, one by one, every 5000 seconds. -- in sequence, one by one, every 5000 seconds.
-- You can change the time to be smaller if that works for you, I used 5000ms just because. -- You can change the time to be smaller if that works for you, I used 5000ms just because.
function connected(sck) local function connected()
tmr.alarm(0,5000,1,do_next) timer = tmr.create()
timer:alarm(5000, tmr.ALARM_AUTO, do_next)
end end
-- @name send_email -- @name send_email
-- @description Will initiated a socket connection to the SMTP server and trigger the connected() function -- @description Will initiated a socket connection to the SMTP server and trigger the connected() function
-- @param subject The email's subject -- @param subject The email's subject
-- @param body The email's body -- @param body The email's body
function send_email(subject,body) local function send_email(subject,body)
count = 0 count = 0
email_subject = subject email_subject = subject
email_body = body email_body = body
...@@ -111,19 +113,13 @@ function send_email(subject,body) ...@@ -111,19 +113,13 @@ function send_email(subject,body)
smtp_socket:connect(SMTP_PORT,SMTP_SERVER) smtp_socket:connect(SMTP_PORT,SMTP_SERVER)
end end
-- Send an email do
send_email( -- Send an email
"ESP8266", send_email(
[[Hi, "ESP8266",
How are your IoT projects coming along? [[Hi,
Best Wishes, How are your IoT projects coming along?
ESP8266]]) Best Wishes,
ESP8266]]
)
end
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
local M local M
do do
-- const -- const
-- luacheck: push no unused
local NEC_PULSE_US = 1000000 / 38000 local NEC_PULSE_US = 1000000 / 38000
local NEC_HDR_MARK = 9000 local NEC_HDR_MARK = 9000
local NEC_HDR_SPACE = 4500 local NEC_HDR_SPACE = 4500
...@@ -17,6 +18,7 @@ do ...@@ -17,6 +18,7 @@ do
local NEC_ONE_SPACE = 1600 local NEC_ONE_SPACE = 1600
local NEC_ZERO_SPACE = 560 local NEC_ZERO_SPACE = 560
local NEC_RPT_SPACE = 2250 local NEC_RPT_SPACE = 2250
-- luacheck: pop
-- cache -- cache
local gpio, bit = gpio, bit local gpio, bit = gpio, bit
local mode, write = gpio.mode, gpio.write local mode, write = gpio.mode, gpio.write
......
...@@ -10,7 +10,7 @@ local host, dir, image = ... ...@@ -10,7 +10,7 @@ local host, dir, image = ...
local doRequest, firstRec, subsRec, finalise local doRequest, firstRec, subsRec, finalise
local n, total, size = 0, 0 local n, total, size = 0, 0
doRequest = function(sk,hostIP) doRequest = function(socket, hostIP) -- luacheck: no unused
if hostIP then if hostIP then
local con = net.createConnection(net.TCP,0) local con = net.createConnection(net.TCP,0)
con:connect(80,hostIP) con:connect(80,hostIP)
......
...@@ -46,7 +46,7 @@ local lfs_t = { ...@@ -46,7 +46,7 @@ local lfs_t = {
end end
end, end,
__newindex = function(_, name, value) __newindex = function(_, name, value) -- luacheck: no unused
error("LFS is readonly. Invalid write to LFS." .. name, 2) error("LFS is readonly. Invalid write to LFS." .. name, 2)
end, end,
......
...@@ -24,8 +24,10 @@ end ...@@ -24,8 +24,10 @@ end
This will exclude any strings already in the ROM table, so the output is the list This will exclude any strings already in the ROM table, so the output is the list
of putative strings that you should consider adding to LFS ROM table. of putative strings that you should consider adding to LFS ROM table.
---------------------------------------------------------------------------------]] ---------------------------------------------------------------------------------
]]--
-- luacheck: ignore
local preload = "?.lc;?.lua", "/\n;\n?\n!\n-", "@init.lua", "_G", "_LOADED", local preload = "?.lc;?.lua", "/\n;\n?\n!\n-", "@init.lua", "_G", "_LOADED",
"_LOADLIB", "__add", "__call", "__concat", "__div", "__eq", "__gc", "__index", "_LOADLIB", "__add", "__call", "__concat", "__div", "__eq", "__gc", "__index",
"__le", "__len", "__lt", "__mod", "__mode", "__mul", "__newindex", "__pow", "__le", "__len", "__lt", "__mod", "__mode", "__mul", "__newindex", "__pow",
......
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
-- then enter the following commands interactively through the UART: -- then enter the following commands interactively through the UART:
-- --
do do
local _,ma,fa=node.flashindex() local sa, ma, fa = node.flashindex()
for n,v in pairs{LFS_MAPPED=ma, LFS_BASE=fa, SPIFFS_BASE=sa} do for n,v in pairs{LFS_MAPPED = ma, LFS_BASE = fa, SPIFFS_BASE = sa} do
print(('export %s=""0x%x"'):format(n, v)) print(('export %s=""0x%x"'):format(n, v))
end end
end end
...@@ -60,7 +60,5 @@ local initTimer = tmr.create() ...@@ -60,7 +60,5 @@ local initTimer = tmr.create()
initTimer:register(1000, tmr.ALARM_SINGLE, initTimer:register(1000, tmr.ALARM_SINGLE,
function() function()
local fi=node.flashindex; return pcall(fi and fi'_init') local fi=node.flashindex; return pcall(fi and fi'_init')
end end)
)
initTimer:start() initTimer:start()
-- luacheck: globals self
if (self.timer) then self.timer:stop() end--SAFETRIM if (self.timer) then self.timer:stop() end--SAFETRIM
-- function _doTick(self) -- function _doTick(self)
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
-- function _provision(self,socket,first_rec) -- function _provision(self,socket,first_rec)
local self, socket, first_rec = ... local self, socket, first_rec = ...
local crypto, file, json, node, table = crypto, file, sjson, node, table local crypto, file, json, node, table = crypto, file, sjson, node, table
local stripdebug, gc = node.stripdebug, collectgarbage local stripdebug, gc = node.stripdebug, collectgarbage
local buf = {} local buf = {}
...@@ -13,11 +13,10 @@ local function getbuf() -- upval: buf, table ...@@ -13,11 +13,10 @@ local function getbuf() -- upval: buf, table
end end
-- Process a provisioning request record -- Process a provisioning request record
local function receiveRec(socket, rec) -- upval: self, buf, crypto local function receiveRec(sck, rec) -- upval: self, buf, crypto
-- Note that for 2nd and subsequent responses, we assme that the service has -- Note that for 2nd and subsequent responses, we assume that the service has
-- "authenticated" itself, so any protocol errors are fatal and lkely to -- "authenticated" itself, so any protocol errors are fatal and likely to
-- cause a repeating boot, throw any protocol errors are thrown. -- cause a repeating boot, throw any protocol errors are thrown.
local config, file, log = self.config, file, self.log
local cmdlen = (rec:find('\n',1, true) or 0) - 1 local cmdlen = (rec:find('\n',1, true) or 0) - 1
local cmd,hash = rec:sub(1,cmdlen-6), rec:sub(cmdlen-5,cmdlen) local cmd,hash = rec:sub(1,cmdlen-6), rec:sub(cmdlen-5,cmdlen)
if cmdlen < 16 or if cmdlen < 16 or
...@@ -25,7 +24,9 @@ local function receiveRec(socket, rec) -- upval: self, buf, crypto ...@@ -25,7 +24,9 @@ local function receiveRec(socket, rec) -- upval: self, buf, crypto
return error("Invalid command signature") return error("Invalid command signature")
end end
local s; s, cmd = pcall(json.decode, cmd) local s
s, cmd = pcall(json.decode, cmd)
if not s then error("JSON decode error") end
local action,resp = cmd.a, {s = "OK"} local action,resp = cmd.a, {s = "OK"}
local chunk local chunk
...@@ -59,15 +60,15 @@ local function receiveRec(socket, rec) -- upval: self, buf, crypto ...@@ -59,15 +60,15 @@ local function receiveRec(socket, rec) -- upval: self, buf, crypto
if not msg then if not msg then
gc(); gc() gc(); gc()
local code, name = string.dump(lcf), cmd.name:sub(1,-5) .. ".lc" local code, name = string.dump(lcf), cmd.name:sub(1,-5) .. ".lc"
local s = file.open(name, "w+") local f = file.open(name, "w+")
if s then if f then
for i = 1, #code, 1024 do for i = 1, #code, 1024 do
s = s and file.write(code:sub(i, ((i+1023)>#code) and i+1023 or #code)) f = f and file.write(code:sub(i, ((i+1023)>#code) and i+1023 or #code))
end end
file.close() file.close()
if not s then file.remove(name) end if not f then file.remove(name) end
end end
if s then if f then
resp.lcsize=#code resp.lcsize=#code
print("Updated ".. name) print("Updated ".. name)
else else
...@@ -80,15 +81,15 @@ local function receiveRec(socket, rec) -- upval: self, buf, crypto ...@@ -80,15 +81,15 @@ local function receiveRec(socket, rec) -- upval: self, buf, crypto
buf = {} buf = {}
elseif action == "dl" then elseif action == "dl" then
local s = file.open(cmd.name, "w+") local dlFile = file.open(cmd.name, "w+")
if s then if dlFile then
for i = 1, #buf do for i = 1, #buf do
s = s and file.write(buf[i]) dlFile = dlFile and file.write(buf[i])
end end
file.close() file.close()
end end
if s then if dlFile then
print("Updated ".. cmd.name) print("Updated ".. cmd.name)
else else
file.remove(cmd.name) file.remove(cmd.name)
...@@ -109,13 +110,13 @@ local function receiveRec(socket, rec) -- upval: self, buf, crypto ...@@ -109,13 +110,13 @@ local function receiveRec(socket, rec) -- upval: self, buf, crypto
file.open(self.prefix.."config.json", "w+") file.open(self.prefix.."config.json", "w+")
file.writeline(json.encode(cmd)) file.writeline(json.encode(cmd))
file.close() file.close()
socket:close() sck:close()
print("Restarting to load new application") print("Restarting to load new application")
node.restart() -- reboot just schedules a restart node.restart() -- reboot just schedules a restart
return return
end end
end end
self.socket_send(socket, resp, chunk) self.socket_send(sck, resp, chunk)
gc() gc()
end end
......
...@@ -9,14 +9,13 @@ ...@@ -9,14 +9,13 @@
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- upvals -- upvals
local crypto, file, json, net, node, table, wifi = local crypto, json, node, wifi =
crypto, file, sjson, net, node, table, wifi crypto, sjson, node, wifi
local error, pcall = error, pcall local error = error
local loadfile, gc = loadfile, collectgarbage local loadfile, gc = loadfile, collectgarbage
local concat, unpack = table.concat, unpack or table.unpack
local self = {post = node.task.post, prefix = "luaOTA/", conf = {}} local self = {post = node.task.post, prefix = "luaOTA/", conf = {}}
-- luacheck: globals DEBUG
self.log = (DEBUG == true) and print or function() end self.log = (DEBUG == true) and print or function() end
self.modname = ... self.modname = ...
self.timer = tmr.create() self.timer = tmr.create()
...@@ -27,15 +26,15 @@ end ...@@ -27,15 +26,15 @@ end
-------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------
-- Utility Functions -- Utility Functions
setmetatable( self, {__index=function(self, func) --upval: loadfile setmetatable( self, {__index=function(obj, func) --upval: loadfile
-- The only __index calls in in LuaOTA are dynamically loaded functions. -- The only __index calls in in LuaOTA are dynamically loaded functions.
-- The convention is that functions starting with "_" are treated as -- The convention is that functions starting with "_" are treated as
-- call-once / ephemeral; the rest are registered in self -- call-once / ephemeral; the rest are registered in self
func = self.prefix .. func func = obj.prefix .. func
local f,msg = loadfile( func..".lc") local f,msg = loadfile( func..".lc")
if msg then f, msg = loadfile(func..".lua") end if msg then f, msg = loadfile(func..".lua") end
if msg then error (msg,2) end if msg then error (msg,2) end
if func:sub(8,8) ~= "_" then self[func] = f end if func:sub(8,8) ~= "_" then obj[func] = f end
return f return f
end} ) end} )
......
-- -- luacheck: globals DEBUG
local function enum(t,log) for k,v in pairs(t)do log(k,v) end end
return {entry = function(msg) return {entry = function(msg)
package.loaded["luaOTA.default"]=nil package.loaded["luaOTA.default"]=nil
local gc=collectgarbage; gc(); gc() local gc=collectgarbage; gc(); gc()
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
]] ]]
-- luacheck: std max
local socket = require "socket" local socket = require "socket"
local lfs = require "lfs" local lfs = require "lfs"
local md5 = require "md5" local md5 = require "md5"
...@@ -31,7 +33,6 @@ local receive_and_parse -- function(esp) ...@@ -31,7 +33,6 @@ local receive_and_parse -- function(esp)
local provision -- function(esp, config, files, inventory, fingerprint) local provision -- function(esp, config, files, inventory, fingerprint)
local read_file -- function(fname) local read_file -- function(fname)
local save_file -- function(fname, data) local save_file -- function(fname, data)
local compress_lua -- function(lua_file)
local hmac -- function(data) local hmac -- function(data)
-- Function-wide locals (can be upvalues) -- Function-wide locals (can be upvalues)
...@@ -164,6 +165,7 @@ receive_and_parse = function(esp) ...@@ -164,6 +165,7 @@ receive_and_parse = function(esp)
local packed_cmd, sig = line:sub(1,#line-6),line:sub(-6) local packed_cmd, sig = line:sub(1,#line-6),line:sub(-6)
-- print("reply:", packed_cmd, sig) -- print("reply:", packed_cmd, sig)
local status, cmd = pcall(json.decode, packed_cmd) local status, cmd = pcall(json.decode, packed_cmd)
if not status then error("JSON decode error") end
if not hmac or hmac(packed_cmd):sub(-6) == sig then if not hmac or hmac(packed_cmd):sub(-6) == sig then
if cmd and cmd.data == "number" then if cmd and cmd.data == "number" then
local data = esp:receive(cmd.data) local data = esp:receive(cmd.data)
...@@ -183,7 +185,7 @@ provision = function(esp, config, inventory, fingerprint) ...@@ -183,7 +185,7 @@ provision = function(esp, config, inventory, fingerprint)
local name, size, mtime, content = f.name, f.size, f.mtime, f.content local name, size, mtime, content = f.name, f.size, f.mtime, f.content
if not cf[name] or cf[name] ~= mtime then if not cf[name] or cf[name] ~= mtime then
-- Send the file -- Send the file
local func, action, cmd, buf local action, cmd, buf
if f.name:sub(-4) == ".lua" then if f.name:sub(-4) == ".lua" then
assert(load(content, f.name)) -- check that the contents can compile assert(load(content, f.name)) -- check that the contents can compile
if content:find("--SAFETRIM\n",1,true) then if content:find("--SAFETRIM\n",1,true) then
...@@ -241,12 +243,11 @@ end ...@@ -241,12 +243,11 @@ end
-- Save contents to the given file -- Save contents to the given file
---------------------------------- ----------------------------------
save_file = function(fname, data) save_file = function(fname, data) -- luacheck: ignore
local file = io.open(fname, "wb") local file = io.open(fname, "wb")
file:write(data) file:write(data)
file:close() file:close()
end end
-------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------
main() -- now that all functions have been bound to locals, we can start the show :-) main() -- now that all functions have been bound to locals, we can start the show :-)
......
...@@ -29,10 +29,12 @@ local TWILIO_ACCOUNT_SID = "xxxxxx" ...@@ -29,10 +29,12 @@ local TWILIO_ACCOUNT_SID = "xxxxxx"
local TWILIO_TOKEN = "xxxxxx" local TWILIO_TOKEN = "xxxxxx"
local HOST = "iot-https-relay.appspot.com" -- visit http://iot-https-relay.appspot.com/ to learn more about this service local HOST = "iot-https-relay.appspot.com" -- visit http://iot-https-relay.appspot.com/ to learn more about this service
-- Please be sure to understand the security issues of using this relay app and use at your own risk. -- Please be sure to understand the security issues of using this relay app and use at your own risk.
local URI = "/twilio/Calls.json" local URI = "/twilio/Calls.json"
function build_post_request(host, uri, data_table) local wifiTimer = tmr.create()
local function build_post_request(host, uri, data_table)
local data = "" local data = ""
...@@ -40,7 +42,7 @@ function build_post_request(host, uri, data_table) ...@@ -40,7 +42,7 @@ function build_post_request(host, uri, data_table)
data = data .. param.."="..value.."&" data = data .. param.."="..value.."&"
end end
request = "POST "..uri.." HTTP/1.1\r\n".. local request = "POST "..uri.." HTTP/1.1\r\n"..
"Host: "..host.."\r\n".. "Host: "..host.."\r\n"..
"Connection: close\r\n".. "Connection: close\r\n"..
"Content-Type: application/x-www-form-urlencoded\r\n".. "Content-Type: application/x-www-form-urlencoded\r\n"..
...@@ -53,7 +55,7 @@ function build_post_request(host, uri, data_table) ...@@ -53,7 +55,7 @@ function build_post_request(host, uri, data_table)
return request return request
end end
local function display(sck,response) local function display(socket, response) -- luacheck: no unused
print(response) print(response)
end end
...@@ -69,7 +71,7 @@ local function make_call(from,to,body) ...@@ -69,7 +71,7 @@ local function make_call(from,to,body)
To = to To = to
} }
socket = net.createConnection(net.TCP,0) local socket = net.createConnection(net.TCP,0)
socket:on("receive",display) socket:on("receive",display)
socket:connect(80,HOST) socket:connect(80,HOST)
...@@ -80,13 +82,13 @@ local function make_call(from,to,body) ...@@ -80,13 +82,13 @@ local function make_call(from,to,body)
end) end)
end end
function check_wifi() local function check_wifi()
local ip = wifi.sta.getip() local ip = wifi.sta.getip()
if(ip==nil) then if(ip==nil) then
print("Connecting...") print("Connecting...")
else else
tmr.stop(0) wifiTimer:stop()
print("Connected to AP!") print("Connected to AP!")
print(ip) print(ip)
-- make a call with a voice message "your house is on fire" -- make a call with a voice message "your house is on fire"
...@@ -95,4 +97,4 @@ function check_wifi() ...@@ -95,4 +97,4 @@ function check_wifi()
end end
tmr.alarm(0,2000,1,check_wifi) wifiTimer:alarm(2000, tmr.ALARM_AUTO, check_wifi)
...@@ -14,23 +14,17 @@ ...@@ -14,23 +14,17 @@
-- Website: http://AllAboutEE.com -- Website: http://AllAboutEE.com
--------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------
require ("mcp23008") local mcp23008 = require ("mcp23008")
-- ESP-01 GPIO Mapping as per GPIO Table in https://github.com/nodemcu/nodemcu-firmware -- ESP-01 GPIO Mapping as per GPIO Table in https://github.com/nodemcu/nodemcu-firmware
gpio0, gpio2 = 3, 4 local gpio0, gpio2 = 3, 4
-- Setup the MCP23008
mcp23008.begin(0x0,gpio2,gpio0,i2c.SLOW)
mcp23008.writeIODIR(0xff)
mcp23008.writeGPPU(0xff)
--- ---
-- @name showButtons -- @name showButtons
-- @description Shows the state of each GPIO pin -- @description Shows the state of each GPIO pin
-- @return void -- @return void
--------------------------------------------------------- ---------------------------------------------------------
function showButtons() local function showButtons()
local gpio = mcp23008.readGPIO() -- read the GPIO/buttons states local gpio = mcp23008.readGPIO() -- read the GPIO/buttons states
...@@ -51,7 +45,13 @@ function showButtons() ...@@ -51,7 +45,13 @@ function showButtons()
print("\r\n") print("\r\n")
end end
tmr.alarm(0,2000,1,showButtons) -- run showButtons() every 2 seconds do
-- Setup the MCP23008
mcp23008.begin(0x0,gpio2,gpio0,i2c.SLOW)
mcp23008.writeIODIR(0xff)
mcp23008.writeGPPU(0xff)
tmr.create():alarm(2000, tmr.ALARM_AUTO, showButtons) -- run showButtons() every 2 seconds
end
...@@ -13,26 +13,17 @@ ...@@ -13,26 +13,17 @@
-- Website: http://AllAboutEE.com -- Website: http://AllAboutEE.com
--------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------
require ("mcp23008") local mcp23008 = require ("mcp23008")
-- ESP-01 GPIO Mapping as per GPIO Table in https://github.com/nodemcu/nodemcu-firmware -- ESP-01 GPIO Mapping as per GPIO Table in https://github.com/nodemcu/nodemcu-firmware
gpio0, gpio2 = 3, 4 local gpio0, gpio2 = 3, 4
-- Setup MCP23008
mcp23008.begin(0x0,gpio2,gpio0,i2c.SLOW)
mcp23008.writeIODIR(0x00) -- make all GPIO pins as outputs
mcp23008.writeGPIO(0x00) -- make all GIPO pins off/low
--- ---
-- @name count() -- @name count()
-- @description Reads the value from the GPIO register, increases the read value by 1 -- @description Reads the value from the GPIO register, increases the read value by 1
-- and writes it back so the LEDs will display a binary count up to 255 or 0xFF in hex. -- and writes it back so the LEDs will display a binary count up to 255 or 0xFF in hex.
local function count() local function count()
local gpio = mcp23008.readGPIO()
local gpio = 0x00
gpio = mcp23008.readGPIO()
if(gpio<0xff) then if(gpio<0xff) then
mcp23008.writeGPIO(gpio+1) mcp23008.writeGPIO(gpio+1)
...@@ -41,5 +32,15 @@ local function count() ...@@ -41,5 +32,15 @@ local function count()
end end
end end
-- Run count() every 100ms
tmr.alarm(0,100,1,count) do
-- Setup MCP23008
mcp23008.begin(0x0,gpio2,gpio0,i2c.SLOW)
mcp23008.writeIODIR(0x00) -- make all GPIO pins as outputs
mcp23008.writeGPIO(0x00) -- make all GIPO pins off/low
-- Run count() every 100ms
tmr.create():alarm(100, tmr.ALARM_AUTO, count)
end
-- test with cloudmqtt.com -- test with cloudmqtt.com
m_dis={} local m_dis = {}
function dispatch(m,t,pl)
if pl~=nil and m_dis[t] then local function dispatch(m,t,pl)
m_dis[t](m,pl) if pl~=nil and m_dis[t] then
end m_dis[t](m,pl)
end
end end
function topic1func(m,pl)
print("get1: "..pl) local function topic1func(_,pl)
print("get1: "..pl)
end end
function topic2func(m,pl)
print("get2: "..pl) local function topic2func(_,pl)
print("get2: "..pl)
end end
m_dis["/topic1"]=topic1func
m_dis["/topic2"]=topic2func do
-- Lua: mqtt.Client(clientid, keepalive, user, pass) m_dis["/topic1"] = topic1func
m=mqtt.Client("nodemcu1",60,"test","test123") m_dis["/topic2"] = topic2func
m:on("connect",function(m) -- Lua: mqtt.Client(clientid, keepalive, user, pass)
print("connection "..node.heap()) local m = mqtt.Client("nodemcu1", 60, "test", "test123")
m:subscribe("/topic1",0,function(m) print("sub done") end) m:on("connect",function(client)
m:subscribe("/topic2",0,function(m) print("sub done") end) print("connection "..node.heap())
m:publish("/topic1","hello",0,0) m:publish("/topic2","world",0,0) client:subscribe("/topic1",0,function() print("sub done") end)
end ) client:subscribe("/topic2",0,function() print("sub done") end)
m:on("offline", function(conn) client:publish("/topic1","hello",0,0)
client:publish("/topic2","world",0,0)
end)
m:on("offline", function()
print("disconnect to broker...") print("disconnect to broker...")
print(node.heap()) print(node.heap())
end) end)
m:on("message",dispatch ) m:on("message",dispatch )
-- Lua: mqtt:connect( host, port, secure, auto_reconnect, function(client) ) -- Lua: mqtt:connect( host, port, secure, function(client) )
m:connect("m11.cloudmqtt.com",11214,0,1) m:connect("m11.cloudmqtt.com",11214,0)
tmr.alarm(0,10000,1,function() local pl = "time: "..tmr.time() tmr.create():alarm(10000, tmr.ALARM_AUTO, function()
m:publish("/topic1",pl,0,0) local pl = "time: "..tmr.time()
end) m:publish("/topic1",pl,0,0)
end)
end
\ No newline at end of file
-- test transfer files over mqtt. -- test transfer files over mqtt.
m_dis={} local m_dis = {}
function dispatch(m,t,pl)
if pl~=nil and m_dis[t] then local function dispatch(m, t, pl)
if pl ~= nil and m_dis[t] then
m_dis[t](m,pl) m_dis[t](m,pl)
end end
end end
function pubfile(m,filename) local function pubfile(m,filename)
file.close() file.close()
file.open(filename) file.open(filename)
repeat repeat
local pl=file.read(1024) local pl = file.read(1024)
if pl then m:publish("/topic2",pl,0,0) end if pl then m:publish("/topic2", pl, 0, 0) end
until not pl until not pl
file.close() file.close()
end end
-- payload(json): {"cmd":xxx,"content":xxx} -- payload(json): {"cmd":xxx,"content":xxx}
function topic1func(m,pl) local function topic1func(m,pl)
print("get1: "..pl) print("get1: "..pl)
local pack = sjson.decode(pl) local pack = sjson.decode(pl)
if pack.content then if pack.content then
...@@ -30,21 +31,22 @@ function topic1func(m,pl) ...@@ -30,21 +31,22 @@ function topic1func(m,pl)
end end
end end
m_dis["/topic1"]=topic1func do
-- Lua: mqtt.Client(clientid, keepalive, user, pass) m_dis["/topic1"]=topic1func
m=mqtt.Client() -- Lua: mqtt.Client(clientid, keepalive, user, pass)
m:on("connect",function(m) local m = mqtt.Client()
print("connection "..node.heap()) m:on("connect",function(client)
m:subscribe("/topic1",0,function(m) print("sub done") end) print("connection "..node.heap())
end ) client:subscribe("/topic1", 0, function() print("sub done") end)
m:on("offline", function(conn) end)
print("disconnect to broker...") m:on("offline", function()
print(node.heap()) print("disconnect to broker...")
end) print(node.heap())
m:on("message",dispatch ) end)
-- Lua: mqtt:connect( host, port, secure, auto_reconnect, function(client) ) m:on("message",dispatch )
m:connect("192.168.18.88",1883,0,1) -- Lua: mqtt:connect( host, port, secure, function(client) )
m:connect("192.168.18.88",1883,0)
end
-- usage: -- usage:
-- another client(pc) subscribe to /topic2, will receive the test.lua content. -- another client(pc) subscribe to /topic2, will receive the test.lua content.
-- and publish below message to /topic1 -- and publish below message to /topic1
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment