Picoweb

Picoweb est un microframework : picoweb, façon bottlepy ou flask.. :

Liens utiles

Ce framework permet de créer des routes à la façon de Bottlepy par exemple.
https://github.com/pfalcon/picoweb

Pré-requis

Etre connecté au réseau wifi pour avoir accès au web :

>>> import network
>>> wifi=network.WLAN(network.STA_IF)
>>> wifi.active(True)
True
>>> wifi.connect("ssid","password")
>>> wifi.isconnected()
True

Ceci peut aussi être automatisé dans un boot.py

Installation

Note : l'installation va nécessiter que l'ESP ait accès au Web au moins pour l'installation. picoweb permet aussi l'utilisation de template ce qui à priori est intéressant.

On fait l'installation à l'aide de pip depuis le micropython !

>>> import upip as pip
>>> pip.install("picoweb")
Installing to: /lib/
Warning: micropython.org SSL certificate is not validated
Installing picoweb 1.8.2 from https://files.pythonhosted.org/packages/c2/22/a1eb0cf52b72e818fe47acadaf8ade200d7c0c7c6fc5acc7b47f53f2a338/picoweb-1.8.2.tar.gz
Installing pycopy-uasyncio 3.7 from https://files.pythonhosted.org/packages/e5/58/80b8b403c52ea88d44844570dbe487d7a4b3045ae0ecad0c9f4dbac0d104/pycopy-uasyncio-3.7.tar.gz
Installing pycopy-pkg_resources 0.2.1 from https://files.pythonhosted.org/packages/05/4a/5481a3225d43195361695645d78f4439527278088c0822fadaaf2e93378c/pycopy-pkg_resources-0.2.1.tar.gz
Installing pycopy-uasyncio.core 2.3.2 from https://files.pythonhosted.org/packages/ca/b2/c5bba0bde7022b6d927a6144c026d7bf310d3f8a20e031571fbf1a08a433/pycopy-uasyncio.core-2.3.2.tar.gz
>>>

Enorme !

Perso, je trouve çà "énorme" de pouvoir aussi facilement installer un truc sur l'ESP à partir de micropython !

Application de test

Ici, une simple webapp de test où on explore les possibilités, notamment d'utiliser du fichier statique... et çà fonctionne !

import network
import picoweb

wifi = network.WLAN(network.STA_IF)
if not wifi.isconnected():
  print('connecting to network...')
  wifi.active(True)
  wifi.connect("DWR-921-6E38","12345678910")
  while not wifi.isconnected():
    pass

print('network config:', wifi.ifconfig())

ipadd=wifi.ifconfig()

app = picoweb.WebApp(__name__)

@app.route("/")
def index(req, resp):
    print(req.method) # info sur la methode requete GET ou POST
    yield from picoweb.start_response(resp)
    yield from resp.awrite("Hello !")
    yield from resp.awrite("Or my <a href='file'>file</a>.")
    # lien renvoie vers une route dediee
    yield from resp.awrite("Or my <a href='boot.py'>file py</a>.")
    yield from resp.awrite("Or my <a href='smoothie.js'>file js</a>.")
    yield from resp.awrite("Or my <a href='html'>page html</a>.")


@app.route("/file")
def static_file(req, resp):
        yield from app.sendfile(resp, "boot.py")

@app.route("/boot.py")
def static_file(req, resp):
        yield from app.sendfile(resp, "boot.py")

@app.route("/smoothie.js")
def static_file(req, resp):
        yield from app.sendfile(resp, "smoothie.js")

@app.route("/html")
def page_html(req, resp):
        page=b"""
                <!DOCTYPE HTML>

        <!-- Debut de la page HTML  -->
        <html>

                <head> <!-- Debut entete -->

                        <meta charset="utf-8" /> <!-- Encodage de la page  -->
                        <title>JavaScript: Test librairie Smoothie</title> <!-- Titre de la page -->

                        <!-- Inclusion librairies / codes Javascript externes -->
                        <script src="smoothie.js" type="text/javascript" ></script>

                        <!-- Debut du code Javascript  -->
                        <script language="javascript" type="text/javascript">


                                // variables globales
                                //var elem; // variable globale élément du DOM   
                      var randomSerie = new TimeSeries(); // crée un objet série de date - fournit par lib smoothie
                                var smoothieGraph = new SmoothieChart({millisPerPixel:50}); // crée un objet graphique smoothie - fournit par lib smoothie

                                window.onload = function () { // au chargement de la page        

                                                // acces aux éléments du DOM 
                                                //elem=document.getElementById("myElem");

                                                // définition de la gestion des évènements du DOM
                                                //elem.setAttribute('onchange', 'fonction()'); // appel la fonction voulue lors de l'évènement-façon HTML

                                                // code a exécuter au chargement de la page                      

                                                // initialisation du graphique smoothie
                                                smoothieGraph.addTimeSeries(randomSerie, { strokeStyle: 'rgba(0, 255, 0, 1)', fillStyle: 'rgba(0, 255, 0, 0.2)', lineWidth: 2 });
                                                smoothieGraph.streamTo(document.getElementById("smoothieCanvas"), 1000); // définition canva et vitesse défilement

                                        setInterval(function() { refreshSmoothieGraph()}, 500); // fixe délai actualisation

                                                // le résultat final est le fruit du mixage entre vitesse de défilement et délai actualisation valeur

                                } // fin onload    

                                // fonctions de gestion des évènement du DOM
                                function fonction(){


                                } // fin fonction 

                                // autres fonctions

                                // fonction d'actualisation de la série de valeur à intervalle régulier
                                function refreshSmoothieGraph(){
                                        randomSerie.append(new Date().getTime(), Math.random() * 4096); // ajoute donnée à la série de données - ici aléatoire          
                                } // fin refresh smootthie

                        </script> <!-- Fin du code Javascript -->

                </head> <!-- Fin entete -->

                <body > <!-- Debut Corps de page HTML -->


                        <!-- === placer ici le code HTML de la page === -->   
                        <canvas id="smoothieCanvas" width="600" height="300"></canvas> <!-- canvas pour graphique smoothie -->   


                </body> <!-- Fin de corps de page HTML  -->

        </html> <!-- Fin de la page HTML  -->

        """
        yield from picoweb.start_response(resp)
        yield from resp.awrite(page)


app.run(debug=-1, port=8000, host =ipadd[0]) # debug -1 pour eviter probleme ulogging

Doc minimale

run( host="127.0.0.1", port=8081, debug=False, lazy_init=False, log=None)

  • mettre debug=-1 pour ne pas avoir message erreur avec ulogging
  • port par défaut est 8081... fixé ce que l'on veut.

Pour l'analyse de la requete, voir ici :

Autour de senfile

COntent Type : https://developer.mozilla.org/fr/docs/Web/HTTP/Headers/Content-Type

Mime Type : https://developer.mozilla.org/fr/docs/Web/HTTP/Basics_of_HTTP/MIME_types

Note : gérer le chargement des librairies :

https://aaronsmith.online/easily-load-an-external-script-using-javascript/ https://webexplorar.com/jquery-check-page-is-fully-loaded-or-not/

Compléments potentiellement utiles

Un tuto pas mal ici : https://itywik.org/2018/10/30/eight-micropython-python-experiments-for-the-esp32/

Il est possible d'utiliser des versions compressées de librairies qui seront décompressés par le navigateur : https://www.alsacreations.com/article/lire/914-compression-pages-html-css-gzip-deflate.html

Ici par exemple, dans le cas de jquery, l'utilisation de minifié + gzipped fait passer une lib de 255Ko à 29Ko... à tester du coup ! https://mathiasbynens.be/demo/jquery-size

Dans le cas précis de Brython, il est aussi possible de mémoire de "compiler" en JS non ?

Test de Brython sur l'ESP

Création d'un répertoire static pour y placer :

  • brython.js : attention le fichier est gros (700Ko et la copie prend un peu de temps) Une autre option serait de la mettre sur un serveur commun sur le réseau local, un Pi.
  • les libs éventuelles

Trop lourd pour l'ESP

Par contre, bien que fonctionnelle, clairement, cette façon de faire est trop lourde pour l'ESP : çà met plusieurs 10aine de secondes à transférer le fichier brython.js... et on n'a pas la lib standard.

Donc, à minima, préférer un accès web : Et si on veut isoler le réseau, mettre un Pi avec fichier de serveur statique, voire même le poste depuis lequel on accède.

A noter que l'adresse à utiliser dans le index.html sera celle sur laquelle on accède au brython.js avec le navigateur. Le plus simple est de la tester en manuel pour éviter les gags...

Création d'un répertoire app pour y placer :

  • index.html
  • scriptBrython.py

Serveur picoweb qui a routes :

  • /app/index.html
  • /app/scriptBrython.py
  • /static/brython.js

Test Ajax

cf essai Brython

Ou bien avec Jquery.

Cf dans ce cas les alternatives légères à jquery d'une part. https://www.technotification.com/2019/06/5-lightweight-jquery-alternatives-2019.html

Autour jQuery :

https://raygun.com/blog/jquery-is-undefined/ https://stackoverflow.com/questions/1956719/jquery-get-is-not-a-function https://www.pierre-giraud.com/jquery-apprendre-cours/creation-requete-ajax/

Test websocket

Libs websockets en Micropython :

Au passage découverte d'un autre projet de webserver : https://github.com/jczic/MicroWebSrv2

Un projet intéressant ici utilisant MicroWebserver et websocket : https://www.rototron.info/raspberry-pi-esp32-micropython-websockets-tutorial/ https://www.rototron.info/raspberry-pi-esp32-micropython-websockets-tutorial/