A simple HTTP server for micropython. It uses asyncio to manage concurrency.
mpremote mip install github:haum/micropython-aiowebserver
import mip
mip.install('github:haum/micropython-aiowebserver')import aiowebserver as web
If you do not use asyncio in your project, just use the run_forever helping
function:
import aiowebserver as web
# Add route handlers
# ...
web.run_forever()With your own asyncio loop, just add an asyncio task:
loop = asyncio.get_event_loop()
loop.create_task(web.start())Defining routes can be done using decorators, that can be chained:
@web.route('GET', '/')
@web.route('GET', '/index.htm')
async def root_handler(rq):
await rq.w('Hello, world!')This defines routes / and /index.htm using GET requests to be served by
root_handler. This function should be a coroutine (async), receives the
request object as parameter. Here, it prints Hello, world!.
To read the data part of the request, use rq.r(n) with n the number of bytes
to read.
To write an answer, use rq.w(str, drain) where str is the string to send and
drain is an optional parameter set to False to not wait for the message to
be sent, for example to buffer messages cut in several small pieces.
It is possible to send static files with
rq.sendfile(path, directory, mimetypes), with path the only
mandatory parameter.
path and directory give respectively the path and the directory in which to
search for this path. Without directory the current working directory is used.
mimetypes is a dictionary, with a mimetype (value) associated to extensions
(key). The special extension * serves as fallback mimetype. A default
dictionary is used in addition to this optional parameter. Using a string
instead of a directory forces the mimetype without reading the default
dictionary.
The function can send gzipped files. The path should be without the .gz
extension, which would automatically be added by the function if the file
without this extension does not exist. If the path is a directory, it will serve
index.htm inside.
The function uses os.stat to compute an ETAG to avoid sending files that are
already in the cache of the browser.
The function uses a lock to avoid sending multiple files in parallel that could saturate the low RAM of the target.
If not specified, the returned status of the page is 200 OK.
To change it, you have to call rq.return_status(code, code_text) before
calling header or write functions. code is the status code, code_text is the
associated text meaning that can be omoitted for a few common statuses.
Redirecting can be done with rq.redirect(url, permanent) where url is the
URL to redirect to and permanent is an optional parameter set to True to
use a 301 Moved Permanently status redirection. This function use header
redirection and therefore should be called alone.
Custom headers can be added with rq.header(name, value). Those headers have to
be added before sending content and after the optional return_status
Special methods help to send Content-Type header: rq.header_html(),
rq.header_text(), rq.header_json().
Some methods help to deal with forms, in particular rq.is_postform(),
rq.decode_postform_data(), rq.is_postjson(), rq.decode_postjson_data() and
rq.decode_query_data().
See forms_and_404.py for usage example.
Note that code to connect to a network or start an access point is not is not present in the examples. You should have setup network before starting them.
See examples folder for examples.
simple.pySimple example with an index pagesimple_port.pySame example, but defining the listening portsimple_ext_loop.pySame example, but without usingrun_foreverhelper function and with another counting taskforms_and_404.pyExample with different form handling (GET, POST, JSON) and a custom 404 error pagestatic.pyExample of static file servingeventsourse.pyExample of SSE/EventSource event communicationwebsocket.pyExample of websocket communication
Initially tested with micropython 1.24 on unix and ESP32-C3 ports.