1 Commits

Author SHA1 Message Date
Marcos Kirsch
9082e223a1 connect_ap.lua example
This was supposed to be PRd by moononournation, but since he never did,
I went ahead and added it to a branch.
2017-07-02 21:49:10 -05:00
6 changed files with 110 additions and 62 deletions

View File

@@ -7,16 +7,16 @@ A (very) simple web server written in Lua for the ESP8266 running the NodeMCU fi
> you are really abusing its intended purpose. When it comes to scoping your ESP8266 > you are really abusing its intended purpose. When it comes to scoping your ESP8266
> applications, the adage Keep It Simple Stupid truly applies. > applications, the adage Keep It Simple Stupid truly applies.
> >
> -- <cite>[Terry Ellison](https://github.com/TerryE)</cite>, nodemcu-firmware maintainer > -- <cite>[Terry Ellison](https://github.com/TerryE)</cite>, nodemcu-firmware maintainer,
Let the abuse begin. Let the abuse begin.
## Features ## Features
* GET, POST, PUT (other methods can be supported with minor changes) * GET, POST, PUT and minor changes to support other methods
* Multiple MIME types * Multiple MIME types
* Error pages (404 and others) * Error pages (404 and others)
* *Server-side execution of Lua scripts* * Server-side execution of Lua scripts
* Query string argument parsing with decoding of arguments * Query string argument parsing with decoding of arguments
* Serving .gz compressed files * Serving .gz compressed files
* HTTP Basic Authentication * HTTP Basic Authentication
@@ -24,9 +24,7 @@ Let the abuse begin.
## How to use ## How to use
1. Modify your local copy of the configuration file httpserver-conf.lua. 1. Upload server files using [nodemcu-uploader](https://github.com/kmpm/nodemcu-uploader).
2. Upload server files using [nodemcu-uploader](https://github.com/kmpm/nodemcu-uploader).
The easiest is to use GNU Make with the bundled Makefile. Open the Makefile and modify the The easiest is to use GNU Make with the bundled Makefile. Open the Makefile and modify the
user configuration to point to your nodemcu-uploader script and your serial port. user configuration to point to your nodemcu-uploader script and your serial port.
Type the following to upload the server code, init.lua (which you may want to modify), Type the following to upload the server code, init.lua (which you may want to modify),
@@ -34,24 +32,28 @@ Let the abuse begin.
make upload_all make upload_all
If you only want to upload just the server code, then type: If you only want to upload the server code, then type:
make upload_server make upload_server
And if you only want to upload just the files that can be served: And if you only want to upload the server files:
make upload_http make upload_http
Restart the server. This will execute included init.lua which will compile the server code, Restart the server. This will execute init.lua which will compile the server code.
configure WiFi, and start the server. Then, assuming init.lua doesn't have it, start the server yourself by typing:
3. Want to serve your own files? Put them under the http/ folder and upload to the chip. dofile("httpserver.lc")(80)
For example, assuming you want to serve myfile.html, upload by typing:
make upload FILE:=http/myfile.html In this example, 80 is the port your server is listening at, but you can change it.
Notice that while NodeMCU's filesystem does not support folders, filenames *can* contain slashes. 2. Want to upload your own files? Move them to the http/ folder. Be careful though,
We take advantage of that and only files that begin with "http/" will be accessible through the server. the flash memory seems to fill up quickly and get corrupted.
All the files you upload must be prefixed with "http/". Wait, what?
Yes: NodeMCU's filesystem does not support folders, but filenames *can* contain slashes.
Only files that begin with "http/" will be accessible through the server.
3. Visit your server from a web browser. 3. Visit your server from a web browser.
@@ -61,19 +63,21 @@ Let the abuse begin.
then index.html is served. By the way, unlike most HTTP servers, nodemcu_httpserver treats the URLs in a then index.html is served. By the way, unlike most HTTP servers, nodemcu_httpserver treats the URLs in a
case-sensitive manner. case-sensitive manner.
## HTTP Basic Authentication. 4. How to use HTTP Basic Authentication.
It's supported. Turn it on in httpserver-conf.lua. Modify variables in configuration file httpserver-conf.lua in order to enable and to configure usernames/passwords.
See comments in that file for more details.
Use it with care and don't fall into a false sense of security: HTTP Basic Authentication should not be When enabled, HTTP Basic Authentication is global to every file served by the server.
considered secure since the server is not using encryption. Username and passwords travel
in the clear.
## Server-side scripting using your own Lua scripts Remember that HTTP Basic Authentication is a very basic authentication protocol, and should not be
considered as secure since the server is not using encryption. Username and passwords travel
in plain text.
Yes, you can upload your own Lua scripts! This is pretty powerful. ## How to use server-side scripting using your own Lua scripts
Just put it under http/ and upload it. Make sure it has a .lua extension.
Your script should return a function that takes three parameters: Similar to static files, upload a Lua script called "http/[name].lua where you replace [name] with your script's name.
The script should return a function that takes three parameters:
return function (connection, req, args) return function (connection, req, args)
-- code goes here -- code goes here
@@ -103,40 +107,42 @@ Let the abuse begin.
#### Hardware description #### Hardware description
This example assumes that you are using a [Wemos D1 Pro](https://wiki.wemos.cc/products:d1:d1_mini_pro) This example assumes that GPIO1 and GPIO2 on the ESP8266 are connected each to a relay
with two relay shields and two reed switches. that can be controlled. How to wire such thing is outside of the scope of this document
[but information is easily found online](https://www.google.com/search?q=opening+a+garage+door+with+a+microcontroller).
The relays are controlled by the microcontroller and act as the push button, The relays are controlled by the microcontroller and act as the push button,
and can actually be connected in parallel with the existing mechanical button. and can actually be connected in parallel with the existing mechanical button.
The switches are wired so that the ESP8266 can tell whether the doors are open
or closed at any given time.
#### Software description #### Software description
This example consists of the following files: This example consists of the following files:
* **garage_door.html**: Static HTML displays a form with all options for controlling the * **garage_door_opener.html**: Static HTML displays a button with a link
two garage doors. to the garage_door_opener.lua script. That's it!
* **garage_door_control.html**: Looks like a garage door remote, how neat! * **garage_door_opener.css**: Provides styling for garage_door_opener.html
* **garage_door_control.css**: Provides styling for garage_door_control.html. just so it looks pretty.
* **garage_door.lua**: Does the actual work. The script performs the desired action on * **garage_door_opener.lua**: Does the actual work. The script first sends
the requested door and returns the results as JSON. a little javascript snippet to redirect the client back to garage_door_opener.html
and then toggles the GPIO2 line for a short amount of time (roughly equivalent to
the typical button press for opening a garage door) and then toggles it back.
* **apple-touch-icon.png**: This is optional. Provides an icon that * **apple-touch-icon.png**: This is optional. Provides an icon that
will be used if you "Add to Home Screen" garage_door_control.html on an iPhone. will be used if you "Add to Home Screen" the demo on an iPhone. Now it looks like an app!
Now it looks like an app!
#### Security implications #### Security implications
Be careful permanently installing something like this in your home. The server provides Be careful permanently installing something like this in your home. The server provides
no encryption. Your only layers of security are the WiFi network's password and simple no encryption. Your only layers of security are the WiFi network's password and simple
HTTP authentication (if you enable it) which sends your password unencrypted. HTTP authentication which sends your password unencrypted.
This script is provided for educational purposes. You've been warned. This script is provided simply as an educational example. You've been warned.
## Not supported ## Not supported
* Other methods: HEAD, DELETE, TRACE, OPTIONS, CONNECT, PATCH * Other methods: HEAD, DELETE, TRACE, OPTIONS, CONNECT, PATCH
* Encryption / SSL * Encryption / SSL
* Old nodemcu-firmware versions prior to January 2017) because I don't bother to test them. * Multiple users (HTTP Basic Authentication)
* Only protect certain directories (HTTP Basic Authentication)
* nodemcu-firmware versions older 1.5.1 (January 2016) because that's what I tested on.
## Contributing ## Contributing
@@ -145,9 +151,7 @@ Let the abuse begin.
and that you add examples for new features. I won't test all your changes myself but I and that you add examples for new features. I won't test all your changes myself but I
am very grateful of improvements and fixes. Open issues in GitHub too, that's useful. am very grateful of improvements and fixes. Open issues in GitHub too, that's useful.
Please keep your PRs focused on one thing. I don't mind lots of PRs. I mind PRs that fix multiple unrelated things. Please follow the coding style as close as possible:
Follow the coding style as closely as possible:
* No tabs, indent with 3 spaces * No tabs, indent with 3 spaces
* Unix (LF) line endings * Unix (LF) line endings
@@ -159,9 +163,8 @@ Let the abuse begin.
The chip is very, very memory constrained. The chip is very, very memory constrained.
* Use a recent nodemcu-firmware. They've really improved memory usage and fixed leaks. * Use a recent nodemcu-firmware with as few optional modules as possible.
* Use only the modules you need. * Use a firmware build without floating point support. This takes up a good chunk of RAM as well.
* Use a firmware build without floating point support if you can. * Any help reducing the memory needs of the server without crippling its functionality is appreciated!
* Any help reducing the memory needs of the server without crippling its functionality is much appreciated! * Compile your Lua scripts in order to reduce their memory usage. The server knows to serve and treat
* Compile your Lua scripts in order to reduce their memory usage. The server knows to serve
both .lua and .lc files as scripts. both .lua and .lc files as scripts.

45
http/connect_ap.lua Normal file
View File

@@ -0,0 +1,45 @@
-- Author: moononournation
-- Notes by Marcos: This example could be improved quite a bit.
-- We should provide a way to return available access points as JSON, then populated
-- a drop down list using JavaScript every 5-10 seconds. I'm not sure it's worth it,
-- however.
return function (connection, req, args)
dofile('httpserver-header.lc')(connection, 200, 'html')
connection:send('<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>Connect AP</title></head><body><h1>Connect AP</h1>')
if req.method == 'GET' then
local ip = wifi.sta.getip()
if not (ip == nil) then
connection:send('<p>IP: ' .. ip .. '</p>')
end
connection:send('<form method="POST">SSID:<br><input type="text" name="ssid"><br>PWD:<br><input type="text" name="pwd"><br><input type="submit" name="submit" value="Submit"></form>')
elseif req.method == 'POST' then
local rd = req.getRequestData()
collectgarbage()
wifi.sta.config(rd['ssid'], rd['pwd'])
wifi.sta.connect()
local joinCounter = 0
local joinMaxAttempts = 15
tmr.alarm(0, 1000, 1, function()
local ip = wifi.sta.getip()
if ip == nil and joinCounter < joinMaxAttempts then
joinCounter = joinCounter + 1
else
if joinCounter >= joinMaxAttempts then
connection:send('<p>Failed to connect to WiFi Access Point.</p>')
else
connection:send('<p>IP: ' .. ip .. '</p>')
end
tmr.stop(0)
joinCounter = nil
joinMaxAttempts = nil
collectgarbage()
end
end)
end
connection:send('</body></html>')
end

View File

@@ -3,7 +3,8 @@
-- Author: Marcos Kirsch -- Author: Marcos Kirsch
local compileAndRemoveIfNeeded = function(f) local compileAndRemoveIfNeeded = function(f)
if file.exists(f) then if file.open(f) then
file.close()
print('Compiling:', f) print('Compiling:', f)
node.compile(f) node.compile(f)
file.remove(f) file.remove(f)

View File

@@ -20,10 +20,9 @@ if (conf.wifi.mode == wifi.SOFTAP) or (conf.wifi.mode == wifi.STATIONAP) then
conf.wifi.accessPoint.config = {} conf.wifi.accessPoint.config = {}
conf.wifi.accessPoint.config.ssid = "ESP-"..node.chipid() -- Name of the WiFi network to create. conf.wifi.accessPoint.config.ssid = "ESP-"..node.chipid() -- Name of the WiFi network to create.
conf.wifi.accessPoint.config.pwd = "ESP-"..node.chipid() -- WiFi password for joining - at least 8 characters conf.wifi.accessPoint.config.pwd = "ESP-"..node.chipid() -- WiFi password for joining - at least 8 characters
conf.wifi.accessPoint.net = {} conf.wifi.accessPoint.ip = "192.168.111.1"
conf.wifi.accessPoint.net.ip = "192.168.111.1" -- conf.wifi.accessPoint.netmask = "255.255.255.0"
conf.wifi.accessPoint.net.netmask="255.255.255.0" -- conf.wifi.accessPoint.gateway = "192.168.111.1"
conf.wifi.accessPoint.net.gateway="192.168.111.1"
end end
-- These apply only when connecting to a router as a client -- These apply only when connecting to a router as a client
if (conf.wifi.mode == wifi.STATION) or (conf.wifi.mode == wifi.STATIONAP) then if (conf.wifi.mode == wifi.STATION) or (conf.wifi.mode == wifi.STATIONAP) then

View File

@@ -14,12 +14,12 @@ wifi.setmode(conf.wifi.mode)
if (conf.wifi.mode == wifi.SOFTAP) or (conf.wifi.mode == wifi.STATIONAP) then if (conf.wifi.mode == wifi.SOFTAP) or (conf.wifi.mode == wifi.STATIONAP) then
print('AP MAC: ',wifi.ap.getmac()) print('AP MAC: ',wifi.ap.getmac())
wifi.ap.config(conf.wifi.accessPoint.config) wifi.ap.config(conf.wifi.accessPoint.config)
wifi.ap.setip(conf.wifi.accessPoint.net) wifi.ap.setip(conf.wifi.accessPoint.ip)
end end
if (conf.wifi.mode == wifi.STATION) or (conf.wifi.mode == wifi.STATIONAP) then if (conf.wifi.mode == wifi.STATION) or (conf.wifi.mode == wifi.STATIONAP) then
print('Client MAC: ',wifi.sta.getmac()) print('Client MAC: ',wifi.sta.getmac())
wifi.sta.config(conf.wifi.station) wifi.sta.config(conf.wifi.station.ssid, conf.wifi.station.pwd, 1)
end end
print('chip: ',node.chipid()) print('chip: ',node.chipid())

View File

@@ -61,19 +61,19 @@ return function (port)
uri.args = {code = 400, errorString = "Bad Request", logFunction = log} uri.args = {code = 400, errorString = "Bad Request", logFunction = log}
fileServeFunction = dofile("httpserver-error.lc") fileServeFunction = dofile("httpserver-error.lc")
else else
local fileExists = false local fileExists = file.open(uri.file, "r")
file.close()
if not file.exists(uri.file) then if not fileExists then
-- print(uri.file .. " not found, checking gz version...")
-- gzip check -- gzip check
if file.exists(uri.file .. ".gz") then fileExists = file.open(uri.file .. ".gz", "r")
-- print("gzip variant exists, serving that one") file.close()
if fileExists then
--print("gzip variant exists, serving that one")
uri.file = uri.file .. ".gz" uri.file = uri.file .. ".gz"
uri.isGzipped = true uri.isGzipped = true
fileExists = true
end end
else
fileExists = true
end end
if not fileExists then if not fileExists then