MicroWebSrv
                                
                                 MicroWebSrv copied to clipboard
                                
                                    MicroWebSrv copied to clipboard
                            
                            
                            
                        A micro HTTP Web server that supports WebSockets, html/python language templating and routing handlers, for MicroPython (used on Pycom modules & ESP32)

--> Go to microWebSrv2 now!
MicroWebSrv is a micro HTTP Web server that supports WebSockets, html/python language templating and routing handlers, for MicroPython (principally used on ESP32 and Pycom modules. Now supports all variants of Pyboard D-series from the makers of Micropython)

Very easy to integrate and very light with 3 files only :
- "microWebSrv.py"- The Web server
- "microWebSocket.py"- The optional support of WebSockets
- "microWebTemplate.py"- The optional templating language for .pyhtml rendered pages
Mini tuto in video by rdagger68 :
Simple but effective :
- Use it to embed a cool Web site in yours modules
- Handle GET, POST, ... requests to interract with user and configure options
- Exchange in JSON format on HTTP methods to make an embedded fullREST API
- Serve files on the fly to export any data to the user
- Use routes and variable route handlers
- Play with AjAX to interact speedly with a Web application
- Make it a captive portal simply
- Use WebSockets for fast and powerful data exchange
- Make html/python files for rendering more efficient web pages
Using microWebSrv main class :
| Name | Function | 
|---|---|
| Constructor | mws = MicroWebSrv(routeHandlers=None, port=80, bindIP='0.0.0.0', webPath="/flash/www") | 
| Start Web server | mws.Start(threaded=True) | 
| Stop Web server | mws.Stop() | 
| Check if Web server is running | mws.IsStarted() | 
| Set URL location for not found page | mws.SetNotFoundPageUrl(url=None) | 
| Get mime type from file extention | mws.GetMimeTypeFromFilename(filename) | 
| Get handler function from route | (routeHandler, routeArgs) = mws.GetRouteHandler(resUrl, method) | 
| Callback function to enable and accept WebSockets | mws.AcceptWebSocketCallback = _acptWS_acptWS(webSocket, httpClient) { } | 
| Maximum length of memory allocated to receive WebSockets data (1024 by default) | mws.MaxWebSocketRecvLen | 
| New thread used for each WebSocket connection (True by default) | mws.WebSocketThreaded | 
| Escape string to HTML usage | MicroWebSrv.HTMLEscape(s) | 
Basic example :
from microWebSrv import MicroWebSrv
mws = MicroWebSrv()      # TCP port 80 and files in /flash/www
mws.Start(threaded=True) # Starts server in a new thread
Using as captive portal :
# To intercept all not found queries and redirect it,
mws.SetNotFoundPageUrl("http://my-device.wifi")
- Can be used with MicroDNSSrv easily.
Using route handlers example :
routeHandlers = [
  ( "relative_url_route_1", "METHOD", handlerFunc_1 ),
  ( "relative_url_route_2", "METHOD", handlerFunc_2 ),
  ( ... )
]
def handlerFunc_1(httpClient, httpResponse, routeArgs=None) :
  print("In HTTP handler 1")
def handlerFunc_2(httpClient, httpResponse, routeArgs=None) :
  print("In HTTP handler 2")
Using directly route handlers decorators example :
@MicroWebSrv.route('/get-test')
def handlerFuncGet(httpClient, httpResponse) :
  print("In GET-TEST HTTP")
@MicroWebSrv.route('/post-test', 'POST')
def handlerFuncPost(httpClient, httpResponse) :
  print("In POST-TEST HTTP")
Using variable routes example :
routeHandlers = [
  ( "/edit/<testid>/<testpath>", "GET", handlerFuncEdit ),
  ( ... )
]
def handlerFuncEdit(httpClient, httpResponse, routeArgs) :
  print("In EDIT HTTP variable route :")
  print(" - testid   = %s" % routeArgs['testid'])
  print(" - testpath = %s" % routeArgs['testpath'])
Or direclty with route handler decorator :
@MicroWebSrv.route('/edit/<testid>/<testpath>')
def handlerFuncEdit(httpClient, httpResponse, routeArgs) :
  print("In EDIT HTTP variable route :")
  print(" - testid   = %s" % routeArgs['testid'])
  print(" - testpath = %s" % routeArgs['testpath'])
Using httpClient class in a route handler function :
| Name | Function | 
|---|---|
| Get MicroWebSrv class | httpClient.GetServer() | 
| Get client address as tuple | httpClient.GetAddr() | 
| Get client IP address | httpClient.GetIPAddr() | 
| Get client TCP port | httpClient.GetPort() | 
| Get client request method | httpClient.GetRequestMethod() | 
| Get client request total path | httpClient.GetRequestTotalPath() | 
| Get client request ressource path | httpClient.GetRequestPath() | 
| Get client request query string | httpClient.GetRequestQueryString() | 
| Get client request query parameters as list | httpClient.GetRequestQueryParams() | 
| Get client request headers as list | httpClient.GetRequestHeaders() | 
| Get client request content type | httpClient.GetRequestContentType() | 
| Get client request content length | httpClient.GetRequestContentLength() | 
| Get client request content | httpClient.ReadRequestContent(size=None) | 
| Get client request form data as list | httpClient.ReadRequestPostedFormData() | 
| Get client request as JSON object | httpClient.ReadRequestContentAsJSON() | 
Using httpResponse class in a route handler function :
| Name | Function | 
|---|---|
| Write switching protocols response | httpResponse.WriteSwitchProto(upgrade, headers=None) | 
| Write generic response | httpResponse.WriteResponse(code, headers, contentType, contentCharset, content) | 
| Write PyHTML rendered response page | httpResponse.WriteResponsePyHTMLFile(filepath, headers=None, vars=None) | 
| Write file directly as response | httpResponse.WriteResponseFile(filepath, contentType=None, headers=None) | 
| Write attached file as response | httpResponse.WriteResponseFileAttachment(filepath, attachmentName, headers=None) | 
| Write OK response | httpResponse.WriteResponseOk(headers=None, contentType=None, contentCharset=None, content=None) | 
| Write JSON object as OK response | httpResponse.WriteResponseJSONOk(obj=None, headers=None) | 
| Write redirect response | httpResponse.WriteResponseRedirect(location) | 
| Write error response | httpResponse.WriteResponseError(code) | 
| Write JSON object as error response | httpResponse.WriteResponseJSONError(code, obj=None) | 
| Write bad request response | httpResponse.WriteResponseBadRequest() | 
| Write forbidden response | httpResponse.WriteResponseForbidden() | 
| Write not found response | httpResponse.WriteResponseNotFound() | 
| Write method not allowed response | httpResponse.WriteResponseMethodNotAllowed() | 
| Write internal server error response | httpResponse.WriteResponseInternalServerError() | 
| Write not implemented response | httpResponse.WriteResponseNotImplemented() | 
Using route handler function example :
def _httpHandlerTestPost(httpClient, httpResponse) :
  formData  = httpClient.ReadRequestPostedFormData()
  firstname = formData["firstname"]
  lastname  = formData["lastname"]
  content   = """\
  <!DOCTYPE html>
  <html>
    <head>
      <meta charset="UTF-8" />
      <title>TEST POST</title>
    </head>
    <body>
      <h1>TEST POST</h1>
      Firstname = %s<br />
      Lastname = %s<br />
    </body>
  </html>
  """ % ( MicroWebSrv.HTMLEscape(firstname),
          MicroWebSrv.HTMLEscape(lastname) )
  httpResponse.WriteResponseOk( headers         = None,
                                contentType     = "text/html",
                                contentCharset  = "UTF-8",
                                content         = content )
Known mime types (content types) :
| File extension | Mime type | 
|---|---|
| .txt | text/plain | 
| .htm | text/html | 
| .html | text/html | 
| .css | text/css | 
| .csv | text/csv | 
| .js | application/javascript | 
| .xml | application/xml | 
| .xhtml | application/xhtml+xml | 
| .json | application/json | 
| .zip | application/zip | 
| application/pdf | |
| .ts | application/typescript | 
| .woff | font/woff | 
| .woff2 | font/woff2 | 
| .ttf | font/ttf | 
| .otf | font/otf | 
| .jpg | image/jpeg | 
| .jpeg | image/jpeg | 
| .png | image/png | 
| .gif | image/gif | 
| .svg | image/svg+xml | 
| .ico | image/x-icon | 
Default index pages order (for http://hostname/) :
| Filename | 
|---|
| index.pyhtml | 
| index.html | 
| index.htm | 
| default.pyhtml | 
| default.html | 
| default.htm | 
Using optional module microWebSocket to connect WebSockets :
- File "microWebSocket.py"must be present to activate WebSockets support
Enable and accept WebSockets :
from microWebSrv import MicroWebSrv
mws = MicroWebSrv()                                    # TCP port 80 and files in /flash/www
mws.MaxWebSocketRecvLen     = 256                      # Default is set to 1024
mws.WebSocketThreaded       = False                    # WebSockets without new threads
mws.AcceptWebSocketCallback = _acceptWebSocketCallback # Function to receive WebSockets
mws.Start(threaded=True)                               # Starts server in a new thread
| Name | Function | 
|---|---|
| Callback function to receive text message | ws.RecvTextCallback = func(webSocket, msg) | 
| Callback function to receive binary data | ws.RecvBinaryCallback = func(webSocket, data) | 
| Callback function when connection was closed | ws.ClosedCallback = func(webSocket) | 
| Send a text message | ws.SendText(msg) | 
| Send a binary message | ws.SendBinary(data) | 
| Check connection state | ws.IsClosed() | 
| Close the connection | ws.Close() | 
Basic example of callback functions :
def _acceptWebSocketCallback(webSocket, httpClient) :
  print("WS ACCEPT")
  webSocket.RecvTextCallback   = _recvTextCallback
  webSocket.RecvBinaryCallback = _recvBinaryCallback
  webSocket.ClosedCallback     = _closedCallback
def _recvTextCallback(webSocket, msg) :
  print("WS RECV TEXT : %s" % msg)
  webSocket.SendText("Reply for %s" % msg)
def _recvBinaryCallback(webSocket, data) :
  print("WS RECV DATA : %s" % data)
def _closedCallback(webSocket) :
  print("WS CLOSED")
Using optional module microWebTemplate for .pyhtml rendered pages :
- File "microWebTemplate.py"must be present to activate .pyhtml pages
- Pages will be rendered in HTML with integrated MicroPython code
| Instruction | Schema | 
|---|---|
| PY | {{ py }}MicroPython code{{ end }} | 
| IF | {{ ifMicroPython condition}}html bloc{{ end }} | 
| ELIF | {{ elifMicroPython condition}}html bloc{{ end }} | 
| ELSE | {{ else }}html bloc{{ end }} | 
| FOR | {{ foridentifierinMicroPython iterator}}html bloc{{ end }} | 
| INCLUDE | {{ includepyhtml_filename}} | 
| ? Â | {{MicroPython expression}} | 
Using {{ py }} :
{{ py }}
  import machine
  from utime import sleep
  test = 123
  def testFunc(x) :
    return 2 * x
{{ end }}
Using {{ if ... }} :
{{ if testFunc(5) <= 3 }}
  <span>titi</span>
{{ elif testFunc(10) >= 15 }}
  <span>tata</span>
{{ else }}
  <span>I like the number {{ test }} !</span>
{{ end }}
Using {{ for ... }} :
{{ for toto in range(testFunc(3)) }}
  <div>toto x 10 equal {{ toto * 10 }}</div>
  <hr />
{{ end }}
Using {{ include ... }} :
{{ include myTemplate.pyhtml }}
Example of a .pyhtml file :
<html>
  <head>
    <title>TEST PYHTML</title>
  </head>
  <body>
    <h1>BEGIN</h1>
    {{ py }}
      def _testFunction(x) :
        return "IN TEST FUNCTION %s" % x
    {{ end }}
    <div style="background-color: black; color: white;">
      {{ for toto in range(3) }}
        This is an HTML test...<br />
        TOTO = {{ toto + 1 }} !<br />
        {{ for toto2 in range(3) }}
          TOTO2 = {{ _testFunction(toto2) }}
        {{ end }}
        Ok good.<br />
      {{ end }}
    </div>
    {{ _testFunction(100) }}<br />
    <br />
    {{ if 2+5 < 3 }}
      IN IF (1)
    {{ elif 10+15 != 25 }}
      IN ELIF (2)
    {{ elif 10+15 == 25 }}
      IN ELIF (3)
    {{ else }}
      IN ELSE (4)
    {{ end }}
  </body>
</html>
By JC`zic for HC² ;')
Keep it simple, stupid :+1: