-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathap_mode.lua
More file actions
160 lines (143 loc) · 6.6 KB
/
Copy pathap_mode.lua
File metadata and controls
160 lines (143 loc) · 6.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
print("Lua WIFI Manager ")
print("https://github.com/gfnord/lua_wifimanager")
-- put module in AP mode
wifi.setmode(wifi.SOFTAP)
print("ESP8266 mode is: " .. wifi.getmode())
-- Set the SSID of the module in AP mode and access password
cfg={}
cfg.ssid="ESP_" .. node.chipid()
cfg.pwd="passw0rd"
print("Chip ID: " .. node.chipid())
print("ESP8266 SSID is: " .. cfg.ssid .. " and PASSWORD is: " .. cfg.pwd)
-- Now you should see an SSID wireless router named ESP_STATION when you scan
-- for available WIFI networks
-- Lets connect to the module from a computer of mobile device. So,
-- find the SSID and connect using the password selected
wifi.ap.config(cfg)
ap_mac = wifi.ap.getmac()
print("AP MAC: " .. ap_mac)
-- create a server on port 80 and wait for a connection, when a connection
-- is coming in function c will be executed
sv = net.createServer(net.TCP, 30) -- 30s timeout
-- Latch: once a credential pair has been accepted, every later request is
-- ignored. sv:close() only closes the listener, so sockets that were already
-- accepted can still deliver data, and without this latch a second request
-- would overwrite the credentials the pending timer is about to save.
-- (docs/KNOWN-ISSUES.md #21)
local provisioning = false
-- Percent- and plus-decode a query-string value. Form input arrives
-- URL-encoded and must be decoded before it can name a real network.
-- (docs/KNOWN-ISSUES.md #1)
local function urldecode(s)
s = string.gsub(s, "+", " ")
return (string.gsub(s, "%%(%x%x)", function(h) return string.char(tonumber(h, 16)) end))
end
-- Accept only what the radio can actually join, so bad input is rejected at
-- the form instead of stranding the device mid-provisioning: SSID 1-32 bytes,
-- passphrase empty (open network) or 8-64 bytes, and no control characters
-- (they are never legitimate in input taken from a query string and cannot
-- be stored in the line-based credentials file).
local function valid_credentials(ssid, password)
local function clean(s)
return type(s) == "string" and #s > 0 and not string.find(s, "%c")
end
return clean(ssid) and #ssid <= 32
and type(password) == "string" and #password <= 64
and (#password == 0 or (#password >= 8 and not string.find(password, "%c")))
end
function receiver(sck, data)
-- parse the SSID and the password out of the request line:
-- GET /?SSID=<ssid>&PASSWORD=<password> HTTP/1.1
-- Delimiters are searched for literally, so an '&' inside the SSID no
-- longer desynchronises the split.
print(string.match(data,"GET"))
local ssid, password
local s = string.find(data, "SSID=", 1, true)
if s then
local p = string.find(data, "&PASSWORD=", s + 5, true)
if p then
local h = string.find(data, " HTTP/1.1", p + 10, true)
if h then
ssid = urldecode(string.sub(data, s + 5, p - 1))
password = urldecode(string.sub(data, p + 10, h - 1))
end
end
end
if ssid and password and valid_credentials(ssid, password) and not provisioning then
provisioning = true
print("ESP8266 connecting to SSID: " .. ssid .. " with PASSWORD: " .. password)
-- close the server and set the module to STATION mode
sv:close()
wifi.setmode(wifi.STATION)
print("ESP8266 mode now is: " .. wifi.getmode())
-- configure the module so it can connect to the network using the received SSID and password
local config_wifi={}
config_wifi.ssid=ssid
config_wifi.pwd=password
wifi.sta.config(config_wifi)
wifi.sta.connect()
print("Setting up ESP8266 for station mode... Please wait.")
-- Poll for a connection; give up after 12 tries (~60 s) and fall back to
-- AP mode instead of retrying forever. ssid and password are locals of
-- receiver captured here, so no later request can change what is saved.
-- (docs/KNOWN-ISSUES.md #3, #21)
local tries = 0
tmr.alarm(2,5000,tmr.ALARM_AUTO,function()
-- Connect wifi
if wifi.sta.getip() == nil then
tries = tries + 1
print('IP unavaiable, waiting...')
if tries >= 12 then
tmr.stop(2)
print('Giving up after '..(tries*5)..'s, returning to AP mode')
file.remove("credentials.lua")
node.restart()
end
else
tmr.stop(2)
-- Save the credentials as plain data lines, one per line. Never as
-- Lua source: this file is read back with file.readline(), so its
-- contents can never execute. (docs/KNOWN-ISSUES.md #2)
file.open("credentials.lua","w+")
file.writeline(ssid)
file.writeline(password)
file.close()
print('The module MAC address is: ' .. wifi.ap.getmac())
print('Config done, IP is '..wifi.sta.getip())
end
end)
end
-- this is the webpage form presented to be configured
local title = "AQS Sensor"
local subtitle = "Configure AQS Sensor Wifi</h2><p>Use the following form to connect this AQS Sensor on your Wifi network"
local response = {"HTTP/1.0 200 OK\r\nServer: NodeMCU on ESP8266\r\nContent-Type: text/html\r\n\r\n"}
response[#response + 1] = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html xmlns=\"http://www.w3.org/1999/xhtml\"><head>"
response[#response + 1] = "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><title>" .. title .. "</title></head><body><div><h1><a>" .. title .. "</a></h1>"
response[#response + 1] = "<form method=\"get\" action=\"/?SSID=\"><div>"
response[#response + 1] = "<h2>" .. subtitle .. "</p></div>"
response[#response + 1] = "<ul ><li><label> SSID </label><div><input name=\"SSID\" type=\"text\" maxlength=\"255\" value=\"\"/>"
response[#response + 1] = "</div> </li><li><label> Password </label><div><input name=\"PASSWORD\" type=\"text\" maxlength=\"255\" value=\"\"/> </div> </li><input type=\"submit\" value=\"Save\" /></ul></form>"
response[#response + 1] = "<div>Powered by <a href=\"https://www.levare.io\">Levare Research Inc @ 2018</a></div></div></body></html>"
response[#response + 1] = "The module MAC address is: " .. ap_mac
-- sends and removes the first element from the 'response' table
local function send(localSocket)
if #response > 0 then
localSocket:send(table.remove(response, 1))
else
localSocket:close()
response = nil
end
end
-- triggers the send() function again once the first chunk of data was sent
sck:on("sent", send)
send(sck)
end
if sv then
print("Server Created.")
sv:listen(80, function(conn) -- listen on port 80
print("Receiving connection on port 80.")
conn:on("receive", receiver)
end)
else
print("ERR: Server was not created.")
end