A micro HTTP Web server that supports WebSockets, html/python language templating and routing handlers, for MicroPython (used on Pycom modules & ESP32)
Also check out the new ESP32 MPY-Jama free IDE and the latest MicroWebSrv2 below:
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
Using optional module microWebSocket to connect WebSockets :
File "microWebSocket.py" must be present to activate WebSockets support
Enable and accept WebSockets :
frommicroWebSrvimportMicroWebSrvmws=MicroWebSrv() # TCP port 80 and files in /flash/wwwmws.MaxWebSocketRecvLen=256# Default is set to 1024mws.WebSocketThreaded=False# WebSockets without new threadsmws.AcceptWebSocketCallback=_acceptWebSocketCallback# Function to receive WebSocketsmws.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=_recvTextCallbackwebSocket.RecvBinaryCallback=_recvBinaryCallbackwebSocket.ClosedCallback=_closedCallbackdef_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 }}
importmachinefromutimeimportsleeptest=123deftestFunc(x) :
return2*x
{{ end }}
{{ fortotoinrange(testFunc(3)) }}
<div>totox10equal {{ toto*10 }}</div><hr/>
{{ end }}
Using {{ include ... }} :
{{ includemyTemplate.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 }}
<divstyle="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}}INIF(1){{elif10+15!= 25}}INELIF(2){{elif10+15 == 25}}INELIF(3){{else}}INELSE(4){{end}}</body></html>
I’ve been wanting to handle web requests using https on a PyCom WiPy 3.0 for awhile now without success. Maybe this is asking too much of the hardware?
I successfully use the POST/GET services from your libraries on a FiPy board (ESP32) when it's uploaded the normal way. It works great, loads webpages from SD, allows me to configure settings in the device and save them back to a config file, all good.
The problem is when I compile the 3 libraries along with the fipy firmware (i've done this successfully many times) I get a check_sum error and the FiPy won't start. I remove the 3 library files and all good, it works again.
Maybe a problem with the compiler and how it 'freezes' .py files, I just don't know why this is happening. For no I will try and load these libraries on the SD card as a work around.
this bug seems to be with the pyboard 'D' but I thought I'd report here in case anyone else is seeing large files that seem to timeout on the microWebSrv. Basically I noticed that sometimes my microWebSrv did not fully transfer large image files while testing.
I tested directly with curl scripts shown below:
curl -X GET http://192.168.110.143:8000/thumb.png > thumb.png
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 71268 100 71268 0 0 205k 0 --:--:-- --:--:-- --:--:-- 205k
nherriot@Zenbook-UX32A ~ $ curl -X GET http://192.168.110.143:8000/thumb.png > thumb.png
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 71268 100 71268 0 0 220k 0 --:--:-- --:--:-- --:--:-- 220k
nherriot@Zenbook-UX32A ~ $ curl -X GET http://192.168.110.143:8000/thumb.png > thumb.png
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
10 71268 10 7403 0 0 2199 0 0:00:32 0:00:03 0:00:29 2199
curl: (18) transfer closed with 63865 bytes remaining to read
You can see where the last curl request fails.
The output from the microWebSrv on the Pyboard 'D' looks like:
Accepted 'client': <socket state=3 timeout=-1 incoming=0 off=0> and 'client address': ('192.168.110.147', 42094)
Processing request HTTP Method: GET Path: /thumb.png Version: HTTP/1.1
Server writing file: www//thumb.png of size: 71268 of type: image/png to host: ('192.168.110.147', 42094)
Last: 612 octets being sent
Accepted 'client': <socket state=3 timeout=-1 incoming=0 off=0> and 'client address': ('192.168.110.147', 42152)
Processing request HTTP Method: GET Path: /thumb.png Version: HTTP/1.1
Server writing file: www//thumb.png of size: 71268 of type: image/png to host: ('192.168.110.147', 42152)
Last: 612 octets being sent
Connected on IP: 192.168.110.143
Accepted 'client': <socket state=3 timeout=-1 incoming=0 off=0> and 'client address': ('192.168.110.147', 42178)
Processing request HTTP Method: GET Path: /thumb.png Version: HTTP/1.1
Server writing file: www//thumb.png of size: 71268 of type: image/png to host: ('192.168.110.147', 42178)
Again we can see the last file never gets sent, and there is no except being called in the WriteResponseFile method. The code looks like:
defWriteResponseFile(self, filepath, contentType=None, headers=None):
""" A method to write a file to the client. It takes the path of the file, calculates it's size and copies the file in chunk sizes of 1024 octets via the low level socket interface. The method first builds the first line of the HTTP request and provides headers, content type, reason code and size of the file. It then does the sending of the file in 1024 octet chunks to the client. If there is a failure in reading the file a WriteREsponseNotFound is sent. If there is a faulure in sending the file to the client a WriteResponseInternalServerError is sent. :param filepath: (e.g. www/style.css) :param contentType: (e.g. text/html) :param headers: (e.g. {'Cache-Control': 'max-age=315360000', 'Last-Modified': 'Fri, 1 Jan 2018 23:42:00 GMT'}) :return: Boolean """try :
size=stat(filepath)[6]
print("Server writing file: {} of size: {} of type: {} to host: {}".format(filepath, size, contentType, self._client._addr ))
ifsize>0 :
withopen(filepath, 'rb') asfile : # Open file for reading in binary modeself._writeBeforeContent(200, headers, contentType, None, size) # Write our HTTP headertry :
buf=bytearray(1024)
whilesize>0 :
x=file.readinto(buf)
ifx<len(buf) :
buf=memoryview(buf)[:x]
print("Last: {} octets being sent".format(x))
self._write(buf) # call up low level socket write functionsize-=xreturnTrueexcept :
self.WriteResponseInternalServerError()
returnFalseexcept :
passself.WriteResponseNotFound()
returnFalse
The file I try and transfer is here - which is not even that large!
I've taken the liberty of adding a lot of print statements and doc strings to the microWebSrv.py file to help me debug. I'll push the doc strings back here today.
If anyone wants to try this out you can find instruction here
I've also reported this to the micropython team here
Things to note that:
I have threading set to True, but it only ever uses a single thread so i have no idea why this would be an issue.
I do use an IRQ Timer which happens every 10 seconds and calls a callback to check WiFi status.
If anyone has clever ways to debug on the embedded board please let me know. :-)
If anyone has an idea why this is happening, or has seen this behaviour before please let me know! :-)
thanks for conceiving and maintaining this fine project.
Similar to #54, we are either getting "maximum recursion depth exceeded" exceptions or blatant "stack overflow" crashes when accessing the filesystem from a route/handler within a threaded webserver. We are using the Pycom FiPy on a recent Pycom firmware version.
Maybe you have any idea about this? Otherwise, let's keep this as a reference for other visitors.
With kind regards,
Andreas.
***ERROR*** A stack overflow in task MPThread has been detected.
abort() was called at PC 0x40099324 on core 1
Backtrace: 0x400991b3:0x3fff0870 0x4009930b:0x3fff0890 0x40099324:0x3fff08b0 0x40095a5d:0x3fff08d0 0x400976a4:0x3fff0900 0x4009765a:0x3ffdd458
[...]
================= CORE DUMP START =================
dE4AABMAAABsAQAA
[...]
================= CORE DUMP END =================
E (6171) esp_core_dump: Skipped 1 tasks with bad TCB!
E (6175) esp_core_dump: Crashed task has been skipped!
I'm trying the MicroWebSrv engine and it seems that serving static pages works fine. Using the controller methods also works fine. However, I have a serious issue with the pyhtml engine.
That's what I did:
I copied microWebSocket.py, microWebSrv.py and microWebTemplate.py in /flash/lib
I created simple static HTML page in /flash/www/index.pyhtml
I used the same initializiation code as from the provided sample
The initialization code:
from microWebSrv import MicroWebSrv
mws = MicroWebSrv()
mws.Start()
The issue is that whenever I try to access http://my-host, my WiPy device hangs for a while and then it seems to restart itself. This happens only when I hit pyhtml pages. Like I said, there is no problem serving static HTML files and there is no problem serving pages from controller methods. I guess I'm missing something. I'm using the latest 'master' source code. Could you please explain what I might be missing in my setup?
I would like to implement something similar to this but before accessing the index.html file allocated inside the /www directory. If I write the same code as before, but using @MicroWebSrv.route('/') then I cannot access the index.html file (as expected).
Is there a way to implement this authentication method? Thanks in advance!
I use your great module for my nodemcu-32s v1.1 board, micropython version 1.9.4, everything looks fine, but when I start webserver with threaded=True, the response is slow, about 4s, however it's ~200ms when threaded mode is False.
I have no idea why this happens, my micropython is clean, no other modules and I use IP to connect the device, so it seems not an DNS issue, could you give me some hints about this?
During development every time I download a new version, I got the following trace:
Traceback (most recent call last):
File "", line 1, in
File "", line 34, in
File "microWebSrv.py", line 224, in Start
OSError: 112
Hello, just tried MicroWebSrv on w WiPy 2.0 and got this error (with the unaltered files):
Traceback (most recent call last):
File "main.py", line 1, in
File "microWebSrv.py", line 21, in
File "microWebSrv.py", line 98, in MicroWebSrv
MemoryError: memory allocation failed, allocating 1784 bytes
MicroPython v1.8.6-760-g90b72952 on 2017-09-01; WiPy with ESP32
Its the line: "_hextochr = dict(('%02x' % i, chr(i)) for i in range(256))"
I could get it running when I uncommented "_hextochr ", but only the URL "test" worked. index.html gave me a 404.
Any idea whats wrong?
(On peut communiquer en francais si vous voulez)
Merci, Ronald Krause
A very good webserver for micropython, even with websocket and template!
My question is, does this powerful lightweight web server work on esp8266? After all, micropython offically support 8266, and 32 and 8266 using same basic MicroPython libraries. Or should I do some modify to make it works.
Thanks a lot!
I'm using writeResponseOK() (I could have used writeResponseJSONOK() but nvm) to send a JSON to my app.
Though I get an error on app side (JSON.parse() failure) when my JSON contains the 'é' character (the only 'exotic' character I send). I found out that i had one character stripped from my response for each 'é'.
I looked at the code of MicroWebSrv.py and found that the data.encode() (in _write() line 578) is computed after len(content) (in WriteResponse() line 644). So in my use case I get data.encode() - len(content) == n where n is the number of 'é' and therefore as many character are stripped at the end of my content.
The fix is to compute the encode() before the len(), maybe contentLength = len(content.encode()) if content else 0 (and that's what I do outside of writeResponseOK() as a quick fix)
s = '\xe9' print(s) # é s.encode() # b'\xc3\xa9' len(s) == len(s.encode()) # False
The example _httpHandlerTestPost method fires but doesn't make it past the line formData = httpClient.ReadRequestPostedFormData(). There is no error message. Looks like the ReadRequestContent method is the culprit. The response stops in this method at b = self._socket.readall().
sys.exc_info is not implemented for the ESP32 yet. It is used in several modules in this repo.
Would it be OK to replace them with Exception.message such as:
Hello JC, I know that loboris makes some modification to your code in order to be compatible with his threads module. Maybe you could do as for DNS server in order to be compatible ?
I was thinking about creating a pull request to take the _serverProcess function and the ability to run the process outside in a while loop at the parent thread process.
def _serverProcess(self) :
self._started = True
while True :
try :
client, cliAddr = self._server.accept()
except Exception as ex :
if ex.args and ex.args[0] == 113 :
break
continue
self._client(self, client, cliAddr)
self._started = False
Proposed Addition
def serverProcessOneCycle(self) :
try :
client, cliAddr = self._server.accept()
except Exception as ex :
if ex.args and ex.args[0] == 113 :
return
self._client(self, client, cliAddr)
Example Usage
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.Init() ## not sure about this first init part
def some_process():
#something awesome
whilte True:
some_process()
try:
mws.serverProcessOneCycle()
except:
print("something went wrong")
Any thoughts, perhaps I didn't consider an already present micropythonic way to do this.
More of a request of a feature than an error.... :-)
It would be great if there was a logging utility to allow logging to be added easily to the web server.
Something like the normal logging utility for python e.g.
I'm using the MicroWebSrv to serve both the back end (rest api) and the front end (made with vue.js). The back end worked fine, but there is some issues with the front end.
The web app packed by Vue.js has 4 folders along with index.html, they are: css, fonts, js, statics. Altough extremely slow when loading the page for the first time, most parts of the page have loaded correctly except for the icons which are fonts. So I took a look at the console, and found some errors, e.g. GET http://192.168.123.108/fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.0509ab09.woff2 net::ERR_ABORTED 403 (Forbidden)
How can I solve this problem? Is there a way to mark this folder as static folder like in Flask?
Many thanks for making MicroWebSrv available!
I got a live web page update loop working with web sockets, but the real page I am trying to port to the esp32 uses Jquery Ajax (with web.py on a Raspberry Pi Zero). It would save me quite some work if I would not have to rewrite/debug the script for web sockets.
The browser developer window tells me that the script hangs in a send.
The server does not register any activity at all.
What am I doing wrong?
testajax.py: testajax.py.txt
testajax.html: testajax.html.txt
For many case , html file will be loaded from flash into a string and then will be pass to WriteResponseOK.
In my application , having upto 50K of heap , but it is fragmented , a html file size of 6KB is failed to loads due to MemoryError
To overcome this , I create a list , load the html in chunk of 100bytes , modified the _write() to accept the list , it write to socket pieces by pieces.
Since micropython doesnt handle heap fragmentation , I think my experiences with this issue will help .
I load one page and I get a core dump. The page loads successfully before the core. The page is a static index.html in /flash/web_admin. MicroWebSrv was compiled into frozen bytecode and I'm running on a WiPy 2.0 with 512KB RAM and 4MB flash. What else do you need to know to troubleshoot this?
from machine import Pin, info
from micropython import mem_info
gc.enable()
running = False
def web_srv_callback(web_srv_pin):
''' If we hit the web_srv_pin launch the web server for configuration '''
# Debounce
from utime import sleep, sleep_ms
sleep(1)
# Only call this function once
global running
if running:
return
from network import WLAN
from microDNSSrv import MicroDNSSrv
from microWebSrv import MicroWebSrv
from microWebTemplate import MicroWebTemplate
wlan = WLAN()
MicroDNSSrv.Create({ '*' : '192.168.4.1' })
if not web_srv_pin.value() == 0:
sleep(1)
return False
# Give the clients 5 minutes to connect
for i in range(300):
if not wlan.isconnected():
sleep(1)
else:
break
if not wlan.isconnected():
return False
gc.collect()
print('gc.mem_free(): ' + str(gc.mem_free()))
print('machine.info(): ' + str(info()))
print('gc.mem_alloc(): ' + str(gc.mem_alloc()))
print('micropython.mem_info(): ' + str(mem_info()))
mws = MicroWebSrv(bindIP='192.168.4.1', webPath="/flash/web_admin/")
mws.SetNotFoundPageUrl("http://SlowBro904.local/")
mws.Start()
sleep(1)
running = True
@MicroWebSrv.route('/')
def handlerFuncGet(httpClient, httpResponse):
print("In GET-TEST HTTP")
@MicroWebSrv.route('/', 'POST')
def handlerFuncPost(httpClient, httpResponse):
print("In POST-TEST HTTP")
web_srv_pin = Pin('P6', mode=Pin.IN, pull=Pin.PULL_UP)
web_srv_pin.callback(trigger=Pin.IRQ_FALLING, handler=web_srv_callback)
System memory info (in bytes)
---------------------------------------------
MPTask stack water mark: 1932
ServersTask stack water mark: 988
TimerTask stack water mark: 2172
IdleTask stack water mark: 600
System free heap: 15860
---------------------------------------------
machine.info(): None
gc.mem_alloc(): 47952
stack: 592 out of 5120
GC: total: 67008, used: 48080, free: 18928
No. of 1-blocks: 525, 2-blocks: 126, max blk sz: 384, max free sz: 553
micropython.mem_info(): None
I have an API which is used to connet/reconnet to a Wifi AP, I wanted this API to WriteResponseOK after the connection is established, however it does send back any response even though the connection was made. For other APIs in my code, httpResponse worked flawlessly, so I think it may be related to wlan methods.
This is the API.
@MicroWebSrv.route('/wifi', 'POST')
def wifi_post(httpClient, httpResponse):
wifi_dict = httpClient.ReadRequestContentAsJSON()
new_ip = wifi.sta_connect(wifi_dict['ssid'], wifi_dict['pass'])
if wifi.is_connected():
if not rtc.is_synced():
print('Syncing RTC...')
rtc.sync()
print(new_ip)
httpResponse.WriteResponseOk()
else:
httpResponse.WriteResponseInternalServerError()
So the above API gets a post request with below json data:
{
"ssid": "new-wifi-ap",
"pass": "12345678"
}
Below is the wifi.sta_connect() method:
def sta_connect(self, ap_ssid, ap_pass, verify_ap=False):
"""
Connect to an Access Point by its SSID and Password
return: string; the IP of the STA
"""
# Attempt connection only if SSID can be found
if verify_ap:
if not self.verify_ap(ap_ssid):
print('Network "' + ap_ssid + '" does not present')
return None
# Disconnect current wifi network
if self.sta.isconnected():
print('Disconnecting from current network...')
self.sta.disconnect()
utime.sleep(1)
self.sta.active(False)
utime.sleep_ms(200)
self.sta.active(True)
utime.sleep_ms(200)
start = utime.ticks_ms()
timeout = 10000
while not self.sta.isconnected():
if utime.ticks_diff(utime.ticks_ms(), start) > timeout:
print('Connecting to "' + ap_ssid + '" Timeout')
if self.ssid and self.pwd:
print('Restore the connection with "' + self.ssid + '"')
try:
self.sta_connect(self.ssid, self.pwd)
except:
pass
else:
return None
break
print('Connecting to "' + ap_ssid + '"...')
self.sta.connect(ap_ssid, ap_pass)
while not self.sta.isconnected() and utime.ticks_diff(utime.ticks_ms(), start) < timeout:
print('Connecting...')
utime.sleep_ms(1500)
else:
print('Network "' + ap_ssid + '" Connected!')
# if successfully connected, store the SSID & Password
self.ssid = ap_ssid
self.pwd = ap_pass
return self.get_sta_ip_addr()
In the REPL I can see the connection was successfully made, then it just got stuck right at where httpResponse.WriteResponseOk() is, in the browser console, that request was in pending status until timeout.
What can be the issue?
Firmware: MicroPython v1.11-240-g519746cae on 2019-08-26; ESP32 module (spiram) with ESP32
Hello JC,
I have a new issue maybe in side effect of loboris network status improvements.
Your server code checks WLAN connection before starting. But in AP mode, the connection is not made, thus not starting the web server.
Maybe you could follow the example of lemariva in his FTP server ?
self.wlan = network.WLAN(network.AP_IF)
if self.wlan.active():
ifconfig = self.wlan.ifconfig()
else:
self.wlan = network.WLAN(network.STA_IF)
if self.wlan.active():
ifconfig = self.wlan.ifconfig()
else:
dbg("No active connection")
Hello,
I was switching to micropython and start to looking for web server, found this wonderful server and decided to test it. I was able to start the server from basic example and access root "/" also open PDF example file, but when decided to test .pyhtml it returns an error (http://192.168.7.96/test.pyhtml):
Thanks for creating the WebSocket support!
When I run the wstest.html example on an ESP32:
websocket = new WebSocket(wsUri);
is throwing the following error:
WebSocket connection to 'ws://192.168.0.39/' failed: Error during WebSocket handshake: Unexpected response code: 501
Looks like there are 2 issues.
def _getConnUpgrade() checks if connection == 'upgrade'. The problem is connection can hold more than 1 attribute such as 'upgrade, keep-alive'. I changed == to in to fix:
if 'upgrade' in self._headers.get('Connection', '').lower()
A bigger problem is that uhashlib is not implemented. MicroWebSocket.py imports sha1 from uhashlib. I don't have a fix. MicroPython lib contains a hashlib library. It contains sha256, but not sha1. Is it possible to use sha256 instead of sha1?
I am having trouble running the example with regard to browsing index.html on an ESP32.
At first the index.html file was not found so I specified webPath='/www/'
This fixed the file not found error.
But then I received a NameException: name _'tryAllocByteArray' is not defined in the ResponseWriteFile() method. I fixed the error by moving the function into the Response class.
Next I received the Exception: can't convert 'bytearray' object to str implicitly in the same ResponseWriteFile() method when it called the write() method. Looks like _client.socket.send(data) expects a string and not a byte array. Normally I would convert with decode('utf-8') but it does not appear to be implemented. Therefore I did an ugly hack of the write() method:
if type(data) == str:
return self._client._socket.send(data)
else:
for b in data:
self._client._socket.send(chr(b))
The page is now loading as HTML with CSS formatting. However, the image is not loading. My write() method hack is throwing an [Errno 104] ECONNRESET. I'm don't know why.
Hi Christophe
Congratulations for your work ¡¡¡. I have a question about the constructor:
Is it possible to change the ports of the websocket process and the webserver process?
For example, the webserver works on port 80 and websocket on 81. I notice that while I have port 80 opened by ws: // the protocol http: // the web server stops working
A lot of thanks
Hi , is it weird that when the Start() run in main thread , everything work , but if I do start_new_thread(Start , ())
, there seem to be no socket._write() occur ! .
Is there anyway to make it async ?
Hello,
thank you for this nice web server project!
I'm using nmap to discover devices in my network. However, as soon as I start the scan in the linux console, MicroWebSrv on my WiPy 3.0 stops working. After that, restarting the server with srv.Start() fails due to [Errno 12] ENOMEM. I found that I need to close the socket first. srv.Stop() will not help, because it closes only, if srv._started is true, which is not the case. Maybe this can be changed? srv._server.close() helps. After that a restart of the server is possible without reseting the whole device.
To trace the cause of the server stop error, I changed the try/except block in microWebSrv.py line 239 to
try :
client, cliAddr = self._server.accept()
except Exception as e :
print(str(e))
break
I get [Errno 128] ENOTCONN when nmap starts.
It seems some connection is being lost. Is there a way to prevent MicroWebSrv from stopping at this position?
nmap has version 7.60
wipy firmware is 1.19.0.b4
micropython has version 1.9.4
Server is started with: