Compare commits
1 Commits
use_file_e
...
connect_ap
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9082e223a1 |
97
README.md
97
README.md
@@ -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
45
http/connect_ap.lua
Normal 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
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user