diff --git a/nodemcu/http/apple-touch-icon.png b/nodemcu/http/apple-touch-icon.png new file mode 100644 index 0000000..de91784 Binary files /dev/null and b/nodemcu/http/apple-touch-icon.png differ diff --git a/nodemcu/http/args.lua b/nodemcu/http/args.lua new file mode 100644 index 0000000..f7a2790 --- /dev/null +++ b/nodemcu/http/args.lua @@ -0,0 +1,26 @@ +return function (connection, req, args) + connection:send("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nCache-Control: private, no-store\r\n\r\n") + connection:send('Arguments') + connection:send('') + connection:send('

Arguments

') + + local form = [===[ +
+ First name:

+ Last name:

+ MaleFemale
+ +
+ ]===] + + connection:send(form) + + connection:send('

Received the following values:

') + connection:send("\n") + connection:send('') +end diff --git a/nodemcu/http/file_list.lua b/nodemcu/http/file_list.lua new file mode 100644 index 0000000..9e92a23 --- /dev/null +++ b/nodemcu/http/file_list.lua @@ -0,0 +1,30 @@ +return function (connection, req, args) + connection:send("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nCache-Control: private, no-store\r\n\r\n") + connection:send('Server File Listing') + connection:send('') + coroutine.yield() + connection:send('

Server File Listing

') + + local remaining, used, total=file.fsinfo() + connection:send("Total size: " .. total .. " bytes
\n") + connection:send("In Use: " .. used .. " bytes
\n") + connection:send("Free: " .. remaining .. " bytes
\n") + + connection:send("

\n") + connection:send("Files:
\n") + connection:send("

\n") + connection:send("

\n") + connection:send('') +end diff --git a/nodemcu/http/garage_door_opener.css b/nodemcu/http/garage_door_opener.css new file mode 100644 index 0000000..bcaa154 --- /dev/null +++ b/nodemcu/http/garage_door_opener.css @@ -0,0 +1,134 @@ +html, body { + height:100%; + margin: 0; + overflow: hidden; +} + +body { + + text-align: center; + background-color: black; + min-height: 100%; + color: black; +} + + +#remote { + background-color: #666; + width: 90%; + border-radius: 30px; + margin: 5% 5% 0; + height: 90%; + padding: 0; +} + +#spacer { + clear: both; + border-top: 1px solid rgba(0, 0, 0, 0.5); + -moz-box-shadow: 1px 1px 1px; + box-shadow: 1px 1px 1px; + margin-right: 30px; + margin-left: 30px; +} + + +.button { + display: inline-block; + width: 43%; + margin: 20px 0 30px; + padding: 40px 0; + border-style: none; + color: rgba(192, 192, 192, 0.5); + text-decoration: none; + border-radius: 20px; + text-shadow: 0 0 1px rgba(0, 0, 0, 0.5); + font-size: 130px; + font-weight: bold; + background-color: #CCC; + -moz-box-shadow: 0 10px rgba(0, 0, 0, 0.25); + box-shadow: 0 10px rgba(0, 0, 0, 0.25); + position: relative; +} + + +.button-1 { + float: left; + margin-left: 5%; +} + +.button-2 { + float: right; + margin-right: 5%; +} + + + +.button span { + + +} + + + +.button:hover span { + + +} + + +.button:active, .button:focus { + + +} + + + +.button:active span { + + +} + + +#label { + font-family: "Lucida Grande", Lucida, Verdana, sans-serif; + background-color: rgba(0, 0, 0, 0.1); + width: 12px; + height: 12px; + display: block; + margin: 20px auto; + -webkit-border-radius: 20px; + -moz-border-radius: 20px; + border-radius: 20px; + text-indent: -99999px; + top: 20px; + position: relative; +} + +#label.start { + +} + +#label.initalizing { + +} + +#label.connection { + background-color: orange; +} + +#label.received { + background-color: orange; +} + +#label.processing { + background-color: orange; +} + +#label.ok { + background-color: green; +} + +#label.bad { + background-color: red; +} + diff --git a/nodemcu/http/garage_door_opener.html b/nodemcu/http/garage_door_opener.html new file mode 100644 index 0000000..cc67ca2 --- /dev/null +++ b/nodemcu/http/garage_door_opener.html @@ -0,0 +1,84 @@ + + + + + + + Garage Remote + + + +
+
+ + I + + + II + +
+
+ + + diff --git a/nodemcu/http/garage_door_opener.lua b/nodemcu/http/garage_door_opener.lua new file mode 100644 index 0000000..ca67617 --- /dev/null +++ b/nodemcu/http/garage_door_opener.lua @@ -0,0 +1,32 @@ +-- garage_door_opener.lua +-- Part of nodemcu-httpserver, example. +-- Author: Marcos Kirsch + +local function pushTheButton(connection, pin) + + -- push the button! + -- Note that the relays connected to the garage door opener are wired + -- to close when the GPIO pin is low. This way they don't activate when + -- the chip is reset and the GPIO pins are in input mode. + gpio.write(pin, gpio.LOW) + gpio.mode(pin, gpio.OUTPUT) + gpio.write(pin, gpio.LOW) + tmr.delay(300000) -- in microseconds + gpio.write(pin, gpio.HIGH) + gpio.mode(pin, gpio.INPUT) + + -- Send back JSON response. + connection:send("HTTP/1.0 200 OK\r\nContent-Type: application/json\r\nCache-Control: private, no-store\r\n\r\n") + connection:send('{"error":0, "message":"OK"}') + +end + +return function (connection, req, args) + print('Garage door button was pressed!', args.door) + if args.door == "1" then pushTheButton(connection, 1) -- GPIO1 + elseif args.door == "2" then pushTheButton(connection, 2) -- GPIO2 + else + connection:send("HTTP/1.0 400 OK\r\nContent-Type: application/json\r\nCache-Control: private, no-store\r\n\r\n") + connection:send('{"error":-1, "message":"Bad door"}') + end +end diff --git a/nodemcu/http/index.html b/nodemcu/http/index.html index 321de45..0db6ace 100644 --- a/nodemcu/http/index.html +++ b/nodemcu/http/index.html @@ -22,12 +22,11 @@
  • Index: This page (static)
  • Zipped: A compressed file (static)
  • Arguments: Parses arguments passed in the URL and prints them. (Lua)
  • -
  • Post: A form that uses POST method, should error. (static)
  • +
  • Post: A form that uses POST method. Displays different content based on HTTP method. (Lua)
  • Garage door opener: Control GPIO lines via the server. (Lua)
  • NodeMCU info: Shows some basic NodeMCU(Lua)
  • List all server files: Displays a list of all the server files. (Lua)
  • Foo: A file that doesn't exist. Should error (404 error)
  • -
  • DaBomb: A working POST example
  • diff --git a/nodemcu/http/node_info.lua b/nodemcu/http/node_info.lua new file mode 100644 index 0000000..86e55eb --- /dev/null +++ b/nodemcu/http/node_info.lua @@ -0,0 +1,26 @@ +local function sendHeader(connection) + connection:send("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nCache-Control: private, no-store\r\n\r\n") + +end + +local function sendAttr(connection, attr, val) + connection:send("
  • ".. attr .. ": " .. val .. "
  • \n") +end + +return function (connection, req, args) + collectgarbage() + sendHeader(connection) + connection:send('A Lua script sample

    Node info

    ') +end diff --git a/nodemcu/http/post.lua b/nodemcu/http/post.lua new file mode 100644 index 0000000..d1ac03d --- /dev/null +++ b/nodemcu/http/post.lua @@ -0,0 +1,33 @@ +return function (connection, req, args) + connection:send("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nCache-Control: private, no-store\r\n\r\n") + connection:send('Arguments') + connection:send('') + connection:send('

    Arguments

    ') + + local form = [===[ +
    + First name:

    + Last name:

    + MaleFemale
    + +
    + ]===] + + if req.method == "GET" then + connection:send(form) + elseif req.method == "POST" then + local rd = req.getRequestData() + -- connection:send(cjson.encode(rd)) + connection:send('

    Received the following values:

    ') + connection:send("\n") + else + connection:send("NOT IMPLEMENTED") + end + + connection:send('') +end diff --git a/nodemcu/http/underconstruction.gif b/nodemcu/http/underconstruction.gif new file mode 100644 index 0000000..7d61c1a Binary files /dev/null and b/nodemcu/http/underconstruction.gif differ diff --git a/nodemcu/http/zipped.html.gz b/nodemcu/http/zipped.html.gz new file mode 100644 index 0000000..8bd5b55 Binary files /dev/null and b/nodemcu/http/zipped.html.gz differ diff --git a/nodemcu/httpserver-b64decode.lua b/nodemcu/httpserver-b64decode.lua new file mode 100755 index 0000000..e18bea6 --- /dev/null +++ b/nodemcu/httpserver-b64decode.lua @@ -0,0 +1,65 @@ +#!/usr/local/bin/lua +-- httpserver-b64decode.lua +-- Part of nodemcu-httpserver, contains b64 decoding used for HTTP Basic Authentication. +-- Based on http://lua-users.org/wiki/BaseSixtyFour by Alex Kloss +-- compatible with lua 5.1 +-- http://www.it-rfc.de +-- Author: Marcos Kirsch + +-- bitshift functions (<<, >> equivalent) +-- shift left +local function lsh(value,shift) + return (value*(2^shift)) % 256 +end + +-- shift right +local function rsh(value,shift) + -- Lua builds with no floating point don't define math. + if math then return math.floor(value/2^shift) % 256 end + return (value/2^shift) % 256 +end + +-- return single bit (for OR) +local function bit(x,b) + return (x % 2^b - x % 2^(b-1) > 0) +end + +-- logic OR for number values +local function lor(x,y) + result = 0 + for p=1,8 do result = result + (((bit(x,p) or bit(y,p)) == true) and 2^(p-1) or 0) end + return result +end + +-- Character decoding table +local function toBase64Byte(char) + ascii = string.byte(char, 1) + if ascii >= string.byte('A', 1) and ascii <= string.byte('Z', 1) then return ascii - string.byte('A', 1) + elseif ascii >= string.byte('a', 1) and ascii <= string.byte('z', 1) then return ascii - string.byte('a', 1) + 26 + elseif ascii >= string.byte('0', 1) and ascii <= string.byte('9', 1) then return ascii + 4 + elseif ascii == string.byte('-', 1) then return 62 + elseif ascii == string.byte('_', 1) then return 63 + elseif ascii == string.byte('=', 1) then return nil + else return nil, "ERROR! Char is invalid for Base64 encoding: "..char end +end + + +-- decode base64 input to string +return function(data) + local chars = {} + local result="" + for dpos=0,string.len(data)-1,4 do + for char=1,4 do chars[char] = toBase64Byte((string.sub(data,(dpos+char),(dpos+char)) or "=")) end + result = string.format( + '%s%s%s%s', + result, + string.char(lor(lsh(chars[1],2), rsh(chars[2],4))), + (chars[3] ~= nil) and string.char(lor(lsh(chars[2],4), + rsh(chars[3],2))) or "", + (chars[4] ~= nil) and string.char(lor(lsh(chars[3],6) % 192, + (chars[4]))) or "" + ) + end + return result +end + diff --git a/nodemcu/httpserver-basicauth.lua b/nodemcu/httpserver-basicauth.lua new file mode 100644 index 0000000..8ff7d25 --- /dev/null +++ b/nodemcu/httpserver-basicauth.lua @@ -0,0 +1,29 @@ +-- httpserver-basicauth.lua +-- Part of nodemcu-httpserver, authenticates a user using http basic auth. +-- Author: Sam Dieck + +basicAuth = {} + +function basicAuth.authenticate(header) + conf = dofile("httpserver-conf.lc") + -- Parse basic auth http header. + -- Returns the username if header contains valid credentials, + -- nil otherwise. + local credentials_enc = header:match("Authorization: Basic ([A-Za-z0-9+/=]+)") + if not credentials_enc then + return nil + end + local credentials = dofile("httpserver-b64decode.lc")(credentials_enc) + local user, pwd = credentials:match("^(.*):(.*)$") + if user ~= conf.auth.user or pwd ~= conf.auth.password then + return nil + end + print("httpserver-basicauth: User \"" .. user .. "\" authenticated.") + return user +end + +function basicAuth.authErrorHeader() + return "WWW-Authenticate: Basic realm=\"" .. conf.auth.realm .. "\"" +end + +return basicAuth diff --git a/nodemcu/httpserver-conf.lua b/nodemcu/httpserver-conf.lua new file mode 100644 index 0000000..854e557 --- /dev/null +++ b/nodemcu/httpserver-conf.lua @@ -0,0 +1,15 @@ +-- httpserver-conf.lua +-- Part of nodemcu-httpserver, contains static configuration for httpserver. +-- Author: Sam Dieck + +local conf = {} + +-- Basic Authentication Conf +local auth = {} +auth.enabled = false +auth.realm = "nodemcu-httpserver" -- displayed in the login dialog users get +auth.user = "user" +auth.password = "password" -- PLEASE change this +conf.auth = auth + +return conf diff --git a/nodemcu/httpserver-error.lua b/nodemcu/httpserver-error.lua new file mode 100644 index 0000000..b4dba56 --- /dev/null +++ b/nodemcu/httpserver-error.lua @@ -0,0 +1,19 @@ +-- httpserver-error.lua +-- Part of nodemcu-httpserver, handles sending error pages to client. +-- Author: Marcos Kirsch + +return function (connection, req, args) + + local function sendHeader(connection, code, errorString, extraHeaders, mimeType) + connection:send("HTTP/1.0 " .. code .. " " .. errorString .. "\r\nServer: nodemcu-httpserver\r\nContent-Type: " .. mimeType .. "\r\n") + for i, header in ipairs(extraHeaders) do + connection:send(header .. "\r\n") + end + connection:send("connection: close\r\n\r\n") + end + + print("Error " .. args.code .. ": " .. args.errorString) + args.headers = args.headers or {} + sendHeader(connection, args.code, args.errorString, args.headers, "text/html") + connection:send("" .. args.code .. " - " .. args.errorString .. "

    " .. args.code .. " - " .. args.errorString .. "

    \r\n") +end diff --git a/nodemcu/httpserver-header.lua b/nodemcu/httpserver-header.lua new file mode 100644 index 0000000..5f01ef7 --- /dev/null +++ b/nodemcu/httpserver-header.lua @@ -0,0 +1,35 @@ +-- httpserver-header.lua +-- Part of nodemcu-httpserver, knows how to send an HTTP header. +-- Author: Marcos Kirsch + +return function (connection, code, extension) + + local function getHTTPStatusString(code) + local codez = {[200]="OK", [400]="Bad Request", [404]="Not Found",} + local myResult = codez[code] + -- enforce returning valid http codes all the way throughout? + if myResult then return myResult else return "Not Implemented" end + end + + local function getMimeType(ext) + local gzip = false + -- A few MIME types. Keep list short. If you need something that is missing, let's add it. + local mt = {css = "text/css", gif = "image/gif", html = "text/html", ico = "image/x-icon", jpeg = "image/jpeg", jpg = "image/jpeg", js = "application/javascript", json = "application/json", png = "image/png", xml = "text/xml"} + -- add comressed flag if file ends with gz + if ext:find("%.gz$") then + ext = ext:sub(1, -4) + gzip = true + end + if mt[ext] then contentType = mt[ext] else contentType = "text/plain" end + return {contentType = contentType, gzip = gzip} + end + + local mimeType = getMimeType(extension) + + connection:send("HTTP/1.0 " .. code .. " " .. getHTTPStatusString(code) .. "\r\nServer: nodemcu-httpserver\r\nContent-Type: " .. mimeType["contentType"] .. "\r\n") + if mimeType["gzip"] then + connection:send("Content-Encoding: gzip\r\n") + end + connection:send("Connection: close\r\n\r\n") +end + diff --git a/nodemcu/httpserver-request.lua b/nodemcu/httpserver-request.lua new file mode 100644 index 0000000..121dbf8 --- /dev/null +++ b/nodemcu/httpserver-request.lua @@ -0,0 +1,115 @@ +-- httpserver-request +-- Part of nodemcu-httpserver, parses incoming client requests. +-- Author: Marcos Kirsch + +local function validateMethod(method) + local httpMethods = {GET=true, HEAD=true, POST=true, PUT=true, DELETE=true, TRACE=true, OPTIONS=true, CONNECT=true, PATCH=true} + -- default for non-existent attributes returns nil, which evaluates to false + return httpMethods[method] +end + +local function uriToFilename(uri) + return "http/" .. string.sub(uri, 2, -1) +end + +local function hex_to_char(x) + return string.char(tonumber(x, 16)) +end + +local function uri_decode(input) + return input:gsub("%+", " "):gsub("%%(%x%x)", hex_to_char) +end + +local function parseArgs(args) + local r = {}; i=1 + if args == nil or args == "" then return r end + for arg in string.gmatch(args, "([^&]+)") do + local name, value = string.match(arg, "(.*)=(.*)") + if name ~= nil then r[name] = uri_decode(value) end + i = i + 1 + end + return r +end + +local function parseFormData(body) + local data = {} + print("Parsing Form Data") + for kv in body.gmatch(body, "%s*&?([^=]+=[^&]+)") do + local key, value = string.match(kv, "(.*)=(.*)") + + print("Parsed: " .. key .. " => " .. value) + data[key] = uri_decode(value) + end + + return data +end + +local function getRequestData(payload) + local requestData + return function () + print("Getting Request Data") + if requestData then + return requestData + else + local mimeType = string.match(payload, "Content%-Type: (%S+)\r\n") + local body_start = payload:find("\r\n\r\n", 1, true) + local body = payload:sub(body_start, #payload) + payload = nil + collectgarbage() + + -- print("mimeType = [" .. mimeType .. "]") + + if mimeType == "application/json" then + print("JSON: " .. body) + requestData = cjson.decode(body) + elseif mimeType == "application/x-www-form-urlencoded" then + requestData = parseFormData(body) + else + requestData = {} + end + + return requestData + end + end +end + +local function parseUri(uri) + local r = {} + local filename + local ext + local fullExt = {} + + if uri == nil then return r end + if uri == "/" then uri = "/index.html" end + questionMarkPos, b, c, d, e, f = uri:find("?") + if questionMarkPos == nil then + r.file = uri:sub(1, questionMarkPos) + r.args = {} + else + r.file = uri:sub(1, questionMarkPos - 1) + r.args = parseArgs(uri:sub(questionMarkPos+1, #uri)) + end + filename = r.file + while filename:match("%.") do + filename,ext = filename:match("(.+)%.(.+)") + table.insert(fullExt,1,ext) + end + r.ext = table.concat(fullExt,".") + r.isScript = r.ext == "lua" or r.ext == "lc" + r.file = uriToFilename(r.file) + return r +end + +-- Parses the client's request. Returns a dictionary containing pretty much everything +-- the server needs to know about the uri. +return function (request) + local e = request:find("\r\n", 1, true) + if not e then return nil end + local line = request:sub(1, e - 1) + local r = {} + _, i, r.method, r.request = line:find("^([A-Z]+) (.-) HTTP/[1-9]+.[0-9]+$") + r.methodIsValid = validateMethod(r.method) + r.uri = parseUri(r.request) + r.getRequestData = getRequestData(request) + return r +end diff --git a/nodemcu/httpserver-static.lua b/nodemcu/httpserver-static.lua new file mode 100644 index 0000000..93ecc2a --- /dev/null +++ b/nodemcu/httpserver-static.lua @@ -0,0 +1,31 @@ +-- httpserver-static.lua +-- Part of nodemcu-httpserver, handles sending static files to client. +-- Author: Marcos Kirsch + +return function (connection, req, args) + dofile("httpserver-header.lc")(connection, 200, args.ext) + --print("Begin sending:", args.file) + -- Send file in little chunks + local continue = true + local bytesSent = 0 + while continue do + collectgarbage() + -- NodeMCU file API lets you open 1 file at a time. + -- So we need to open, seek, close each time in order + -- to support multiple simultaneous clients. + file.open(args.file) + file.seek("set", bytesSent) + local chunk = file.read(256) + file.close() + if chunk == nil then + continue = false + else + coroutine.yield() + connection:send(chunk) + bytesSent = bytesSent + #chunk + chunk = nil + --print("Sent" .. args.file, bytesSent) + end + end + --print("Finished sending:", args.file) +end diff --git a/nodemcu/httpserver.lua b/nodemcu/httpserver.lua new file mode 100644 index 0000000..2b0376a --- /dev/null +++ b/nodemcu/httpserver.lua @@ -0,0 +1,123 @@ +-- httpserver +-- Author: Marcos Kirsch + +-- Starts web server in the specified port. +return function (port) + + local s = net.createServer(net.TCP, 10) -- 10 seconds client timeout + s:listen( + port, + function (connection) + + -- This variable holds the thread used for sending data back to the user. + -- We do it in a separate thread because we need to yield when sending lots + -- of data in order to avoid overflowing the mcu's buffer. + local connectionThread + + local allowStatic = {GET=true, HEAD=true, POST=false, PUT=false, DELETE=false, TRACE=false, OPTIONS=false, CONNECT=false, PATCH=false} + + local function onRequest(connection, req) + collectgarbage() + local method = req.method + local uri = req.uri + local fileServeFunction = nil + + print("Method: " .. method); + + if #(uri.file) > 32 then + -- nodemcu-firmware cannot handle long filenames. + uri.args = {code = 400, errorString = "Bad Request"} + fileServeFunction = dofile("httpserver-error.lc") + else + local fileExists = file.open(uri.file, "r") + file.close() + + if not fileExists then + -- gzip check + fileExists = file.open(uri.file .. ".gz", "r") + file.close() + + if fileExists then + print("gzip variant exists, serving that one") + uri.file = uri.file .. ".gz" + uri.ext = uri.ext .. ".gz" + end + end + + if not fileExists then + uri.args = {code = 404, errorString = "Not Found"} + fileServeFunction = dofile("httpserver-error.lc") + elseif uri.isScript then + fileServeFunction = dofile(uri.file) + else + if allowStatic[method] then + uri.args = {file = uri.file, ext = uri.ext} + fileServeFunction = dofile("httpserver-static.lc") + else + uri.args = {code = 405, errorString = "Method not supported"} + fileServeFunction = dofile("httpserver-error.lc") + end + end + end + connectionThread = coroutine.create(fileServeFunction) + coroutine.resume(connectionThread, connection, req, uri.args) + end + + local function onReceive(connection, payload) + collectgarbage() + local conf = dofile("httpserver-conf.lc") + local auth + local user = "Anonymous" + + -- parse payload and decide what to serve. + local req = dofile("httpserver-request.lc")(payload) + print("Requested URI: " .. req.request) + if conf.auth.enabled then + auth = dofile("httpserver-basicauth.lc") + user = auth.authenticate(payload) -- authenticate returns nil on failed auth + end + + if user and req.methodIsValid and (req.method == "GET" or req.method == "POST" or req.method == "PUT") then + onRequest(connection, req) + else + local args = {} + local fileServeFunction = dofile("httpserver-error.lc") + if not user then + args = {code = 401, errorString = "Not Authorized", headers = {auth.authErrorHeader()}} + elseif req.methodIsValid then + args = {code = 501, errorString = "Not Implemented"} + else + args = {code = 400, errorString = "Bad Request"} + end + connectionThread = coroutine.create(fileServeFunction) + coroutine.resume(connectionThread, connection, req, args) + end + end + + local function onSent(connection, payload) + collectgarbage() + if connectionThread then + local connectionThreadStatus = coroutine.status(connectionThread) + if connectionThreadStatus == "suspended" then + -- Not finished sending file, resume. + coroutine.resume(connectionThread) + elseif connectionThreadStatus == "dead" then + -- We're done sending file. + connection:close() + connectionThread = nil + end + end + end + + connection:on("receive", onReceive) + connection:on("sent", onSent) + + end + ) + -- false and nil evaluate as false + local ip = wifi.sta.getip() + if not ip then ip = wifi.ap.getip() end + print("nodemcu-httpserver running at http://" .. ip .. ":" .. port) + return s + +end diff --git a/nodemcu/inithttp.lua b/nodemcu/inithttp.lua new file mode 100644 index 0000000..60e5faf --- /dev/null +++ b/nodemcu/inithttp.lua @@ -0,0 +1,78 @@ +-- Begin WiFi configuration + +local wifiConfig = {} + +-- wifi.STATION -- station: join a WiFi network +-- wifi.AP -- access point: create a WiFi network +-- wifi.wifi.STATIONAP -- both station and access point +wifiConfig.mode = wifi.STATIONAP -- both station and access point + +wifiConfig.accessPointConfig = {} +wifiConfig.accessPointConfig.ssid = "ESP-"..node.chipid() -- Name of the SSID you want to create +wifiConfig.accessPointConfig.pwd = "ESP-"..node.chipid() -- WiFi password - at least 8 characters + +wifiConfig.stationPointConfig = {} +wifiConfig.stationPointConfig.ssid = "Scalar24" -- Name of the WiFi network you want to join +wifiConfig.stationPointConfig.pwd = "Fb274Gh@12G1" -- Password for the WiFi network + +-- Tell the chip to connect to the access point + +wifi.setmode(wifiConfig.mode) +print('set (mode='..wifi.getmode()..')') +print('MAC: ',wifi.sta.getmac()) +print('chip: ',node.chipid()) +print('heap: ',node.heap()) + +wifi.ap.config(wifiConfig.accessPointConfig) +wifi.sta.config(wifiConfig.stationPointConfig.ssid, wifiConfig.stationPointConfig.pwd) +wifiConfig = nil +collectgarbage() + +-- End WiFi configuration + +-- Compile server code and remove original .lua files. +-- This only happens the first time afer the .lua files are uploaded. + +local compileAndRemoveIfNeeded = function(f) + if file.open(f) then + file.close() + print('Compiling:', f) + node.compile(f) + file.remove(f) + collectgarbage() + end +end + +local serverFiles = {'httpserver.lua', 'httpserver-basicauth.lua', 'httpserver-conf.lua', 'httpserver-b64decode.lua', 'httpserver-request.lua', 'httpserver-static.lua', 'httpserver-header.lua', 'httpserver-error.lua'} +for i, f in ipairs(serverFiles) do compileAndRemoveIfNeeded(f) end + +compileAndRemoveIfNeeded = nil +serverFiles = nil +collectgarbage() + +-- Connect to the WiFi access point. +-- Once the device is connected, you may start the HTTP server. + +local joinCounter = 0 +local joinMaxAttempts = 5 +tmr.alarm(0, 3000, 1, function() + local ip = wifi.sta.getip() + if ip == nil and joinCounter < joinMaxAttempts then + print('Connecting to WiFi Access Point ...') + joinCounter = joinCounter +1 + else + if joinCounter == joinMaxAttempts then + print('Failed to connect to WiFi Access Point.') + else + print('IP: ',ip) + -- Uncomment to automatically start the server in port 80 + dofile("httpserver.lc")(80) + end + tmr.stop(0) + joinCounter = nil + joinMaxAttempts = nil + collectgarbage() + end + +end) +