WEB Server



  • Any good news about having a web server?



  • @eric-waai Apparently the pycom boards do not have enough memory to run it. I contacted @jczic and that was his reply.

    @pierrot10 , if you are still around, what board did you use?

    I am looking for a solution where the pycom board (Lopy4 in my case) would be set as an AP, display a form via a webapp to let the user update some parameters.

    I have seen solutions that work on other ESP32 boards.

    Any help would be good. Setting the device as AP is a nice thing to have, but some examples on how to use this functionality would be handy.



  • i somehow just son't get this to work on a fipy.

    i tried using the code given here with the microwebserver but i don't get a browser to display anything.

    i think the fipy should put data on the uart and i don't get anything there either.

    any ideas?

    this is the code i have in main.py

    
    from microWebSrv import MicroWebSrv
    
    # ----------------------------------------------------------------------------
    
    def _httpHandlerTestGet(httpClient, httpResponse) :
    	content = """\
    	<!DOCTYPE html>
    	<html lang=en>
            <head>
            	<meta charset="UTF-8" />
                <title>TEST GET</title>
            </head>
            <body>
                <h1>TEST GET</h1>
                Client IP address = %s
                <br />
    			<form action="/test" method="post" accept-charset="ISO-8859-1">
    				First name: <input type="text" name="firstname"><br />
    				Last name: <input type="text" name="lastname"><br />
    				<input type="submit" value="Submit">
    			</form>
            </body>
        </html>
    	""" % httpClient.GetIPAddr()
    	httpResponse.WriteResponseOk( headers		 = None,
    								  contentType	 = "text/html",
    								  contentCharset = "UTF-8",
    								  content 		 = content )
    
    def _httpHandlerTestPost(httpClient, httpResponse) :
    	formData  = httpClient.ReadRequestPostedFormData()
    	firstname = formData["firstname"]
    	lastname  = formData["lastname"]
    	content   = """\
    	<!DOCTYPE html>
    	<html lang=en>
    		<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 )
    
    # ----------------------------------------------------------------------------
    
    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")
    
    # ----------------------------------------------------------------------------
    
    routeHandlers = [
    	( "/test",	"GET",	_httpHandlerTestGet ),
    	( "/test",	"POST",	_httpHandlerTestPost )
    ]
    
    from network import WLAN
    wlan = WLAN();
    wlan.init(mode=WLAN.AP, ssid='fipy test', auth=(WLAN.WPA2, 'qwerty123'))
    wlan.ifconfig( id     = 1,
                   config = ('10.0.0.10', '255.255.255.0', '10.0.0.254', '10.0.0.254' ) )
    
    srv = MicroWebSrv(routeHandlers=routeHandlers)
    srv.SetNotFoundPageUrl('index.html')
    srv.MaxWebSocketRecvLen     = 256
    srv.WebSocketThreaded		= True
    srv.AcceptWebSocketCallback = _acceptWebSocketCallback
    srv.Start(threaded=True)
    
    from microDNSSrv import MicroDNSSrv
    srv = MicroDNSSrv.Create( {
    	"*"   : "10.0.0.254" } )
    print("Done")
    
    # ----------------------------------------------------------------------------
    


  • @jczic Hello, Thank for your reply. I was concentrated on creating a nice web page with jquery mobile, but .... (laugh), lopy did not have enough space to store the library :o) :o).
    I created a very smaller nice welcome web page.

    However, if I wrote this is to say, after I modified the default index.html, the popup windows appear after the WiFi connection. So that finally work,

    What you lastly wrote, we are agree is to have any url request redirect to the index.html?

    I tried

    fconfig( id     = 1,
                   config = ('0.0.0.0', '255.255.255.0', '10.0.0.254', '0.0.0.0' ) ) # (ip, subnet_mask, gateway, DNS_server)
    

    It's look not working. It ask me to enter again the WiFi password but it does not accept it. Any way, it's not so important. Ir would nice that if I enter only 'localhost' the my smartphone browser, or any caracter, it forward to index.html. but it take too much of your time I can leave

    wlan.ifconfig( id     = 1,
                   config = ('10.0.0.254', '255.255.255.0', '10.0.0.254', '10.0.0.254' ) ) # (ip, subnet_mask, gateway, DNS_server)
    

    :o)

    I also changed to

    srv.SetNotFoundPageUrl('index.html')
    

    in that way, all "notFoundPage is redirected to the index.



  • @pierrot10 Okay, you must to configure the IP interface else LoPy wifi set the DNS server tout 0.0.0.0.
    Set the configuration IP with the same IP addr for the DNS.

    After, you must to use MicroDNSSrv tout catch all names to the same IP { "*" : "10.0.0.254" }.

    All web requests will be directed tout this IP.
    Thé MicroWebSrv have not page for "www.a-test.com" for exemple.
    You must set your default page URL if a page IS not round.

    boot.py is just the first "launched" file and it can configure the terminal to the serial UART input/output.



  • @jczic Hello!! Thank a lot for this example. That help but I can not make it working at 100%

    When I connect to my WIFI (with my smartphone) it does not open a browser with the page. But it's not critical. If I can do it , it's great, if not, the user can be connect to the SSID and then open a broser but it would be necessary that all request into the browser (any URL) foward to the 192.168.4.1 web page.

    However, when I enter the url www.nothin.fr (or something else), the content of 192.168.4.1 is display.

    I observed when I enter www.google.ch, it does display the content of 192.168.4.1. It display an error page not found.
    I observed that all https reuqest display a not page found, and it look like id only the http request display the 192.168.4.1 content.

    Can it be possible?

    I also could configure an new iP for my AP.

    wlan.ifconfig( id     = 1,
                   config = ('10.0.0.254', '255.255.255.0', '10.0.0.254', '10.0.0.254' ) )
    

    that work when I enter 10.0.0.254 in my browser.

    However, the srv.SetNotFoundPageUrl

    srv.SetNotFoundPageUrl('my-captive-portal.mydevice.com')
    

    never display a page. But I do not understand the URL you gave.
    Does mydevise.com is the name of my poly4 devise?
    If yes how can I set the name of my devise

    Or should I change it with (or with an URL of my web site to see a result)?

    srv.SetNotFoundPageUrl('map.google.com')
    

    Should it be an external web site or a page of my LoPy devise like /test.

    Last question :o).
    Is
    _httpHandlerTestPost and _httpHandlerTestGet necessary in that exercice?

    or should I use to create some additional page like

    routeHandlers = [
    	( "/sensors",	"GET",	_httpHandlerTestGet ),
    	( "/configure",	"POST",	_httpHandlerTestPost )
    ]
    

    Last last question.
    I saw in your github, the boot.py as this code

    from    os      import dupterm
    from    machine import UART
    
    uart = UART(0, 115200)
    dupterm(uart)
    

    I have o copied it and my boo.py is empty.
    Is an error from me?
    What does the boot.py code exactely?

    Thank fro your support and your great help, it help and help me to learn as well!!!!!
    Pierrot



  • @jczic That great!!!! Thank, I will try it later!!!!! Thank



  • @pierrot10 Sorry pierrot but that works (I have just tested) :)
    You must to configure MicroDNSServer to respond to all domains with your IP :

    from microDNSSrv import MicroDNSSrv
    srv = MicroDNSSrv.Create( {
    	"*"   : "192.168.4.1" } )
    

    and you must to configure MicroWebSrv with a redirection on a "not found" page :

    srv.SetNotFoundPageUrl('my-captive-portal.mydevice.com')
    

    If you want to change the default IP and configuration, try this complet code in main.py :

    
    from microWebSrv import MicroWebSrv
    
    # ----------------------------------------------------------------------------
    
    def _httpHandlerTestGet(httpClient, httpResponse) :
    	content = """\
    	<!DOCTYPE html>
    	<html lang=fr>
            <head>
            	<meta charset="UTF-8" />
                <title>TEST GET</title>
            </head>
            <body>
                <h1>TEST GET</h1>
                Client IP address = %s
                <br />
    			<form action="/test" method="post" accept-charset="ISO-8859-1">
    				First name: <input type="text" name="firstname"><br />
    				Last name: <input type="text" name="lastname"><br />
    				<input type="submit" value="Submit">
    			</form>
            </body>
        </html>
    	""" % httpClient.GetIPAddr()
    	httpResponse.WriteResponseOk( headers		 = None,
    								  contentType	 = "text/html",
    								  contentCharset = "UTF-8",
    								  content 		 = content )
    
    def _httpHandlerTestPost(httpClient, httpResponse) :
    	formData  = httpClient.ReadRequestPostedFormData()
    	firstname = formData["firstname"]
    	lastname  = formData["lastname"]
    	content   = """\
    	<!DOCTYPE html>
    	<html lang=fr>
    		<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 )
    
    # ----------------------------------------------------------------------------
    
    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")
    
    # ----------------------------------------------------------------------------
    
    routeHandlers = [
    	( "/test",	"GET",	_httpHandlerTestGet ),
    	( "/test",	"POST",	_httpHandlerTestPost )
    ]
    
    from network import WLAN
    wlan = WLAN();
    wlan.init(mode=WLAN.AP, ssid='MYDEVICE WIFI', auth=(WLAN.WPA2, 'azerty123'))
    wlan.ifconfig( id     = 1,
                   config = ('10.0.0.254', '255.255.255.0', '10.0.0.254', '10.0.0.254' ) )
    
    srv = MicroWebSrv(routeHandlers=routeHandlers)
    srv.SetNotFoundPageUrl('my-captive-portal.mydevice.com')
    srv.MaxWebSocketRecvLen     = 256
    srv.WebSocketThreaded		= False
    srv.AcceptWebSocketCallback = _acceptWebSocketCallback
    srv.Start()
    
    from microDNSSrv import MicroDNSSrv
    srv = MicroDNSSrv.Create( {
    	"*"   : "10.0.0.254" } )
    
    # ----------------------------------------------------------------------------
    

    Just connect your computer or smartphone to wifi MYDEVICE WIFI with pass azerty123 and a captive popup will be opened on your main page :)



  • @pierrot10 Okay yes, I see.
    But at the moment, this is not possible with MicroDNSSrv. I must to add special domaine name like "apple" etc... to automatically open a popup window on smartphones and computers who connects to Wi-Fi AP.
    But now, you must to start MicroDNSSrv to resolve names ...
    You can open a browser and type a domain name (or catch * wildcards domains).



  • @jczic :o), what do you meen by

    You want to make a captive portal ?
    

    I would like to display basic information about my node. Because my Lopy4 is LoRa Node. So when the owner is close to the node, he connect to the SSID and he got basic information. But for that I have to write the index.html page with those basic information. In order to make it simple for the user, when he is connected to the SSID, his smartphone browser open and display the info without an additionnal action from the user, excepted to be connected to the SSID.

    Thank for the link microDNSSrv.py.
    I will look at this, for sure



  • @pierrot10 You want to make a captive portal ?
    But for the moment, you can use https://github.com/jczic/MicroDNSSrv because LoPy and others Pycom modules have not DNS server to resolve names :)



  • @jczic Thank a lot for your reply. Yes, I moved IsStarted to another instruction and I got the right message. My Lopy4 act as an AP and the SSID is LoPy4. Do you have any idea, how, it can open a browser and display /www/index.html, as soon as I am connected to my LoPy4 network?
    I am very happy, because I could successfully add your library to my sensor project (pysense). No worries for the images. It's not important for the moment, but I will have find.... :o)



  • @pierrot10
    For "WEB NOT started", if you starts MicroWebSrv in threaded mode, you can call IsStarted() function after a little instant because a thread must be started to change the result of IsStarted() to true.
    For your terminal error, I don't understand... Sorry :/



  • @jczic Actually, I changed

    srv.Start(threaded=True)
    

    to

    srv.Start(threaded=False)
    

    then I changed again to

    srv.Start(threaded=True)
    

    and I synced and my terminal printed me that error

    Reading file status
    [1/3] Writing file main.py
    [2/3] Writing file www/pdf.jpg
    Upload failed. Please reboot your device manually.
    

    I also wonder why

    if srv.IsStarted():
    	print('Web started')
    else:
    	print('WEB NOT started')
    

    it always return me

    WEB NOT started
    

    while it the server is started as I can print a page from 192.168.4.1 ??

    Thank for your clarification and your help!!!
    Cheers



  • @livius Thank a lot, it really better!!!! It work!!!
    Sorry for the format. I edit my post but it did let me to manually add the 3 ```. I will take to not do it again for sure.

    I am very new with pycom, I started this week-end.

    My goal is to have a very simple web server. The goal is when I connect to the Poly4 as AP, it automatically redirect to the /www/index.html.

    Is possible to do it?

    Additionnaly, I add a pdf.jpg into the folder /www/ and I can not sync it. However, I edit my global and project setting and I add jpg and pdf to the filed

    sync_file_types
    

    Did I missed to modify something in the setting?

    Next step, I will edit my pysense project and try to integrate the web server, but for now I try to make this project link text working.

    Many thank fro your help



  • @river :')



  • @jczic I'm following your library, discovered some days ago.
    Many thanks for sharing! I will dig in a couple of days with it, at the moment I miss some more "elaborated" example (for novices as me).
    Will try to make a kind of wifimanager saving/retrieving values to flash in order to connect to a WiFi or keep settings.
    Again, many thanks for sharing this, great work!



  • @pierrot10 Yes, the default IP for LoPy is 192.168.4.1.
    If you want, you can also use https://github.com/jczic/MicroDNSSrv to resolve names and connect to the good IP.



  • @pierrot10
    if you start lopy in AP mode then it default ip is 192.168.*4*.1 not 0

    and what you got on UART? It start without an error?

    and please format your future post
    http://commonmark.org/help/



  • @jczic I am trying hard to make working MicroWebServer. In fact IsStarted return me always false. I really have no idea what I have to do.
    I tried different solution but without succes. WOuld it be possible to tell what wrong I did? Did I missed apackage?

    I supposed, I should connect the the WLAN 'lypo4_1' and open a browser with the 192.168.0.1?

    My structure is
    myProject/flash/www
    myProject/js
    myProject/main.py
    myProject/boot.py
    myProject/microWebSocket.py
    myProject/microWebSrv.py
    myProject/microWebTemplate.py

    Here is my code

    #import socket
    #import time
    #import binascii
    import pycom

    from network import WLAN
    #from pysense import Pysense
    from microWebSrv import MicroWebSrv

    #py = Pysense()
    print('\n\n** Init WLAN mode and WAP2')
    wlan = WLAN(mode=WLAN.AP,ssid="lypo4_1",auth=(WLAN.WPA2,'00000000')) # we call the constructor without params
    print('\n\n** Next...')

    ----------------------------------------------------------------------------

    def _httpHandlerTestGet(httpClient, httpResponse) :
    content = """
    <!DOCTYPE html>
    <html lang=fr>
    <head>
    <meta charset="UTF-8" />
    <title>TEST GET</title>
    </head>
    <body>
    <h1>TEST GET</h1>
    Client IP address = %s
    <br />
    <form action="/test" method="post" accept-charset="ISO-8859-1">
    First name: <input type="text" name="firstname"><br />
    Last name: <input type="text" name="lastname"><br />
    <input type="submit" value="Submit">
    </form>
    </body>
    </html>
    """ % httpClient.GetIPAddr()
    httpResponse.WriteResponseOk( headers = None,
    contentType = "text/html",
    contentCharset = "UTF-8",
    content = content )

    def _httpHandlerTestPost(httpClient, httpResponse) :
    formData = httpClient.ReadRequestPostedFormData()
    firstname = formData["firstname"]
    lastname = formData["lastname"]
    content = """
    <!DOCTYPE html>
    <html lang=fr>
    <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 )

    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")

    print('\n\n** routeHandle')
    routeHandlers = [
    ( "/test", "GET", _httpHandlerTestGet ),
    ( "/test", "POST", _httpHandlerTestPost )
    ]
    print('\n\n** MicroWebserv')
    #srv = MicroWebSrv(routeHandlers=routeHandlers)
    #srv = MicroWebSrv(routeHandlers=None, port=80, webPath="/flash/www")
    srv = MicroWebSrv()
    srv.MaxWebSocketRecvLen = 256
    srv.WebSocketThreaded = False
    srv.AcceptWebSocketCallback = _acceptWebSocketCallback
    #srv.Start(threaded=True)
    srv.Start()
    print('\n\n** Ready')

    if srv.IsStarted():
    print('Web started')
    else:
    print('WEB NOT started')


 

Hello World?

Pylife on Kickstarter - November 2018








Back Us On Kickstarter >

Pycom on Twitter