Résolu sur le forum : Borne Wallbox Pulsar Plus 7,4 kW sur abonnement 6 kVA : quel délestage avant accord copro (urgent)Ma panne diagnostiquée — réponse sous 48 h29 €

Programmer le pcDuino : Pyduino : Réseau :Serveur TCP / Http / HTML + Javascript + Ajax : Afficher dans le navigateur client un graphique avec la librairie Dygraphs à partir d’un fichier de données horodatées sélectionné dans une liste déroulante listant le contenu d’un répertoire et mis à jour par requête Ajax vers le serveur Pyduino, supportant l’affichage de 1 à n série de données.

Électroniquemis à jour le 23 avril 2023

Programmer le pcDuino : Pyduino : Réseau :Serveur TCP / Http / HTML + Javascript + Ajax : Afficher dans le navigateur client un graphique avec la librairie Dygraphs à partir d’un fichier de données horodatées sélectionné dans une liste déroulante listant le contenu d’un répertoire et mis à jour par requête Ajax vers le serveur Pyduino, supportant l’affichage de 1 à n série de données.

Ce que l’on va faire ici

  • Dans ce code, je vous montre comment mettre en place un serveur TCP / Http / HTML + Javascript + Ajax qui permet la mise à jour par requête Ajax d’un graphique à partir d’un fichier de données, graphique fourni par une librairie graphique Javascript, Dygraphs.
  • Le point intéressant ici : la sélection du fichier de données se fait à partir d’une liste déroulante contenant le contenu d’un répertoire du serveur. Il devient ainsi très simple de visualiser plusieurs graphes différents !
  • Second oint intéressant : le serveur supporte l’affichage de 1 à n série de données (jusqu’à 10 par défaut..)
  • La librairie Dygraphs est à installer en local sur un miniPC par exemple.

Ce code est « all-in-one » associant dans le même fichier le code Pyduino/Python créant le serveur, la page HTML initiale, le code javascript côté client et la réponse Ajax Serveur. Facile à déboguer, à adapter… et un seul code à exécuter côté serveur !

  • On utilise ici :
    • une fonction dédiée pour fournir la page HTML+ code Javascript, rendant le code plus facile à maintenir.
    • une fonction dédiée pour l’envoi de la requête AJax.

Note technique

  • Un peu à la façon des « poupées gigognes » notre code est écrit en Python…
    • qui intègre lui-même la page HTML
      • qui intègre elle-même le code Javascript qui sera exécuté côté client !
        • qui intègre elle-même le code gérant l’envoi de la requête Ajax et la gestion de la réponse.
  • Le serveur TCP gère quand à lui la requête GET initiale et les requêtes Ajax.

Pré-requis

  • un mini-PC (pcDuino conseillé) avec système Lubuntu opérationnel. Voir si besoin la page d’accueil du pcDuino
  • Langage Python (2.7) et l’IDE Pyduino ou l’éditeur Geany installés. Voir si besoin : Logiciel pour développer avec Pyduino
  • ma librairie pyDuino installée : voir si besoin : Télécharger et installer Pyduino sur le pcDuino
  • Un serveur Http opérationnel ainsi que la librairie Javascript utilisée doivent également avoir été installés au préalable sur le miniPC.
  • Pour plus de détails, voir : Installer des librairies Javascript locales

Schéma fonctionnel

  • Le code Pyduino communique avec l’interface réseau du système qui assure la connexion avec le client distant. On communique également ici avec le fichier texte :
  • Noter que ce code fonctionne aussi bien en éthernet (filaire) qu’en wifi (sans fil) sous réserve que la connexion matérielle soit opérationnelle.

Le réseau utilisé

  • Note : le poste fixe peut évidemment être le poste depuis lequel vous accédez au pcDuino par VNC, au moins en phase d’essai.

Matériel nécessaire

Système

  • Le pcDuino
  • connecté à un réseau local actif associant :
    • un routeur (une box internet typiquement) +/- un switch réseau
    • d’autres postes sur le réseau, notamment un poste fixe ou une tablette.
    • voire un poste distant sur le web
  • Si on utilise le wifi, on utilisera le dongle wifi ou une clé USB wifi au lieu de l’interface réseau ethernet. Mais pour un simple test, rester en filaire, c’est plus simple !

E/S

  • Pas utilisées.

Instructions de montage

  • Simplement connecter le pcDuino au réseau, ce qui est normalement déjà le cas si vous travaillez en accès VNC !

Le montage à réaliser

Le fichier *.py

Copier/coller ce code dans l’éditeur Geany :

#!/usr/bin/python
# -*- coding: utf-8 -*-

# exemple pyDuino – par X. HINAULT – www.mon-club-elec.fr
# Juillet 2013 – Tous droits réservés – GPLv3
# voir : https://github.com/sensor56/pyDuino

# Tester l’envoi d’une requete Ajax, l’envoi d’une reponse et la gestion d’une reponse Ajax

from pyduino import * # importe les fonctions Arduino pour Python

import numpy as np

# entete declarative
compt=0 # variable de comptage
ipLocale=Ethernet.localIP() # auto – utilise l’ip de l’interface eth0 du systeme

#ipLocale= »192.168.1.25″ # manuel – attention : utiliser la meme IP qu’une interface reseau du systeme
# pour connaitre les interfaces reseau sur le systeme : utiliser la commande $ ifconfig

print ipLocale # affiche l’adresse IP

port=8080 # attention port doit etre au dessus de 1024 sinon permission refusee par securite – 8080 pour http

serverHTTP=EthernetServer(ipLocale, port) # crée un objet serveur utilisant le port 8080 = port HTTP > 1024

data=None # Tableau Numpy  global des donnees

files=None # liste des fichiers

#— setup —
def setup():

        # — serveur TCP —
        global serverHTTP, ipLocale, port

        #serverHTTP.begin(10) # initialise le serveur – fixe nombre max connexion voulu
        serverHTTP.begin() # initialise le serveur – nombre max connexion par defaut = 5

        print (« Serveur TCP actif avec ip : «  + ipLocale +  » sur port : «  + str(port) )
#— fin setup

# — loop —
def loop():

        global serverHTTP

        print (« Attente nouvelle connexion entrante… »)
        clientDistant, ipDistante = serverHTTP.clientAvailable() # attend client entrant
        # code bloque ici tant que pas client ! Si present, on recupere d’un coup objet client ET son ip

        print « Client distant connecte avec ip : »+str(ipDistante) # affiche IP du client

        #— requete client —
        requete=serverHTTP.readDataFrom(clientDistant) # lit les donnees en provenance client d’un coup

        print requete # affiche requete recue

        # analyse de la requete

        #====== si requete ajax ======
        if requete.startswith(« GET /ajax »): # si la requete recue est une requete ajax

                lignesRequete=requete.splitlines() # recupere la requete est list de lignes
                print lignesRequete[0]  # premiere ligne = la requete utile

                params=lignesRequete[0].split(‘=’) # isole la valeur – requete de la forme /ajax=val= donc split « = » isole la valeur
                param=int(params[1]) # 2eme valeur est la valeur recue avec requete ajax
                print param

                #— reponse serveur requete formulaire —
                reponse=( # ( … ) pour permettre multiligne..
                httpResponse() # entete http OK 200 automatique fournie par la librairie Pyduino

                # contenu reponse AJAX
                +

                reponseAJAX(param) # voir la fonction separee – pour clarte du code – ici on passe le parametre

                                +« \n« ) # fin reponse

                serverHTTP.writeDataTo(clientDistant, reponse) # envoie donnees vers client d’un coup

                print « Reponse envoyee au client distant : « 
                #print (bytes(reponse))
                print (reponse) # affiche la reponse envoyee

        #====== si requete GET simple = premiere requete => envoi page HTML+JS initiale ======
        elif requete.startswith(« GET »): # si la requete commence par GET seul = premiere page

                print « Requete GETrecue valide »

                #– code Pyduino a executer au besoin
                global compt
                compt=0 # RAZ compt

                #— reponse serveur requete initiale —
                reponse=( # ( … ) pour permettre multiligne..
                httpResponse() # entete http OK 200 automatique fournie par la librairie Pyduino

                # contenu page HTML+ JS initiale
                +

                pageInitialeHTMLJS() # voir la fonction separee – pour clarte du code

ÉlectroniqueChamp électrique : les notions fondamentales expliquées simplement

                +« \n« ) # fin reponse

                serverHTTP.writeDataTo(clientDistant, reponse) # envoie donnees vers client d’un coup

                print « Reponse envoyee au client distant : « 
                #print (bytes(reponse))
                print (reponse) # affiche la reponse envoyee

        #====== si requete pas valide ======
        else : # sinon requete pas valide

                print (« Requete pas valide »)

        #====== une fois la page envoyée ======
        #serverHTTP.close()
        # remarque : le socket = serveur doit rester ouvert

        # quand on quitte l’application: la connexion TCP reste active un peu donc erreur si re-execution trop rapide du code
        # on peut utiliser un port voisin dans ce cas…

        delay(10) # entre 2 loop()

# — fin loop —

#========== fonction fournissant la page HTML + JS initiale incluant code javascript AJAX ======
def pageInitialeHTMLJS():

        # code Python a executer avant envoyer page

        #chemin fichier initial – celui du jour voir aucun

        myDataPath=(« data/text/ »)

        path=homePath()+myDataPath  # chemin du répertoire à utiliser
        #filename= »testdata.txt » # nom du fichier
        filename=« data_ »+today(« _ »,-1)+« .txt » # nom du fichier du jour
        filepath=path+filename # chemin du fichier

        #– lecture du fichier —
        myFile=open(filepath,‘r’) # ouverture en lecture
        print (« Contenu du fichier : « )
        myFile.seek(0) # se met au debut du fichier

        linesList=myFile.readlines() # lit le fichier – renvoie list

        myFile.close() # fermeture du fichier

        #print linesList

        «  » »
        # test le nombre de data dispo
        testData=linesList[0].split(« , »)
        print testData
        print len(testData)
        nombreData=len(testData)-1 # la premiere colonne correspond a x, ensuite les series y
        «  » »

        # on fixe arbitrairement le nombre de series max possible car la MAJ se fait par AJax et nemodifie pas le nombre de serie
        # TODO : MAJ auto nombre serie cote client – voir Ajax
        nombreData=10# nombre max de series

        # titre serie pour Dygraphs – creation liste des series au format « y1= », « y2″, .. »yn= »
        listeSeries=«  »
        for i in range(nombreData):
                if i==nombreData-1: # si derniere data
                        listeSeries=listeSeries+« \ »y »+str(i+1)+« =\ »«  # pas de virgule
                else:
                        listeSeries=listeSeries+« \ »y »+str(i+1)+« =\ », »  # sinon virgule
        # fin for

        print listeSeries

        # donnees sous forme d’une chaine
        # format ligne data dans la page HTML « x,y\n »
        dataGraph=«  »

        for dataLine in linesList[:-1]: # defile lignes sauf la derniere
                dataGraph=dataGraph+« \ »« +dataLine.rstrip(\n)+ » \\n \ » + » + « \n«  # dataLine.rstrip(‘\n’) = enleve \n de la ligne

        dataGraph=dataGraph+« \ »« +linesList[1].rstrip(\n)+ » \\n \ » «  # derniere ligne sans le +

        # Note : lors envoi page initiale : donnees envoyees au sein code JS
        # lors envoi reponse ajax : donnees envoyees en tant que chaine texte

         # l’envoi initial d’un tableau de valeurs permet de fixer la largeur du graphique

        # chargement de la liste des fichiers dans la liste déroulante

        global files

        dirPath=homePath()+« data/text »
        print dirPath

        files=listfiles(dirPath)
        print files

        optionsFiles=«  »

        for filename in files:
                print filename

                optionsFiles=optionsFiles+« \t\t\t<option value=\ »« +filename+« \ » label=\ »« +filename+« \ »> »+filename+« </option> \n« 
                print optionsFiles

        # options du graphique Dygraph a utiliser
        optionsGraph=(«  » »
        labels: [ « x », «  » »

        +
        listeSeries
        +
        «  » »], // labels series
        width : 800, // largeur
        height: 400, // hauteur
        //valueRange: [0,4095], // plage valeurs Y
        showRangeSelector: true // affiche l’outil de selection plage voulue
        «  » »

        ) # fin optionsGraph

        contenuPageInitialeHTMLJS=( # debut page HTML
«  » »
<!DOCTYPE html>
<html>
    <head>
        <meta charset= »utf-8″ />
        <title>Test reponse Ajax</title>

        <!– Debut du code Javascript  –>
        <script language= »javascript » type= »text/javascript »>
        <!–

        // code javascript par X. HINAULT – www.mon-club-elec.fr – tous droits reserves – 2013 – GPL v3

        function path(jsFileNameIn) { // fonction pour fixer chemin absolu                              
                        var js = document.createElement(« script »);
                        js.type = « text/javascript »;
                        //js.src =  » https://www.mon-club-elec.fr/mes_javascripts/dygraphs/ »+jsFileNameIn; // <=== serveur externe – modifier chemin ++ si besoin
                        //js.src = « http://127.0.0.1/javascript/dygraphs/ »+jsFileNameIn; // serveur local
                        //js.src = « http://web.archive.org/web/20210804223007/https://www.mon-club-elec.fr/pmwiki_mon_club_elec/javascript/rgraph/ »+jsFileNameIn; // chemin local  – fichier doit etre a la racine serveur
                        js.src = « http:// »+window.location.hostname+ »:80″+ »/javascript/dygraphs/ »+jsFileNameIn; // si utilisation server http local port 80

                        document.head.appendChild(js);                                  
                        //alert(js.src); // debug

                } // fin fonction path

                //—- fichiers a charger —                            
                path(‘dygraph-combined.js’); // fichier simplifiant acces a tous les fichiers de la librairie dygraph

        //— variables globales —
        var myselect=null; // objet global
        var mytextarea=null; // objet global

        var textInputDygraphs=null; // objet global

        //var delai=1000; // delai en ms entre 2 requetes AJAX – pas utilise ici
                var val=0;

        //———- fonction initiale executee au lancement —–
        window.onload = function () { // au chargement de la page

                        // dygraphs
                        textInputDygraphs=document.getElementById(« valeurDygraphs »);

                        g = new Dygraph( // cree l’objet du graphique

                        // containing div
                        document.getElementById(« graphdiv »), // objet div utilise appele par son nom

                        // CSV ou chemin fichier CSV.

                        // donnees valides au format x,y1, y2, …, yn \n
                        // x = horodatage ou chiffre
                        // horodatages valides : voir http://dygraphs.com/data.html#csv
«  » »
        +
        dataGraph
        +
«  » »,

                        //– parametres a utiliser pour le graphique
                        {
«  » »
        +
        optionsGraph
        +
«  » »
                        } // fin parametres

                        ); // fin declaration Dygraph

                        // liste deroulante

                        myselect=document.getElementById(« liste »);
                        mytextarea=document.getElementById(« text »);

                        mytextarea.value= »Selectionner un fichier »;

                        for (var i=0; i<myselect.options.length; i++){

                                //println(« Option index « +i + « : » + myselect.options[i].text +  » ( » + myselect.options[i].value + « ) ») // affiche la liste des options – debug

                        } // fin for                  

            // fonction de gestion d’un changement select – ici placee dans le code JS initial
                        myselect.onchange=function () {

                                var index=this.selectedIndex
                                //println (« Index courant = »+index +  » soit :  » + this.options[index].text); // this represent myselect – debug

                                requeteAjax(index,manageReponseAjax);
                                //println(« Envoi requete Ajax »); – debug

                                } // fin fonction onchangeSelect

            //setTimeout(function () {requeteAjax(manageReponseAjax);}, delai); // setTimeOut avec fonction inline : 1er appel de la fonction requete Ajax
            // nb : setTimeout() n’applique delai qu’une fois
        } // fin onload

        //—- fonctions utiles —

         function println(textIn) { // fonction pour ajouter un element a la page – utile ++ pour debug

        // Ajouter un element a la page sans effacer le reste
        //var txt= »Hello »;

                                        var txt=textIn;

                                        var newtext = document.createTextNode(txt);
                                        document.body.appendChild(newtext);

                                        document.body.appendChild(document.createElement(« br »)); // ajoute saut de ligne

                                        document.body.appendChild(newtext);  

                                } // fin println

        //———- fonction de requete AJAX —–
        function requeteAjax(chaineIn, callback) { // la fonction recoit en parametre la fonction de callback qui gere la reponse Ajax
                        // la fonction de callback appelee sera celle definie dans setTimeOut : manageAjaxData
                        var xhr = XMLHttpRequest(); // declare objet de requete AJAX  – OK Firefox

                        xhr.open(« GET », « /ajax= »+chaineIn+ »= », true); // definition de la requete envoyee au serveur ici : GET /ajax
                        xhr.send(null); // envoi de la requete

ÉlectroniqueBien chauffer son atelier d’électronique : confort, sécurité et continuité de travail

                        xhr.onreadystatechange = function() { // fonction de gestion de l’evenement onreadystatechange
                                if (xhr.readyState == 4 && xhr.status == 200) { // si reponse OK
                                        callback(xhr.responseText); // appel fonction gestion reponse en passant texte reponse en parametre
                                } // fin if
                        }; // fin function onreadystatechange

                } // fin fonction requeteAjax

                //—— fonction qui sera utilisee en fonction de callback = gestion de la reponse Ajax
                function manageReponseAjax(stringDataIn) { // la fonction recoit en parametre la chaine de texte de la reponse Ajax

                        //println (stringDataIn) // debug

                        mytextarea.value=stringDataIn; // affiche le contenu du fichier dans le champ

                        // ici la fonction actualise le graphique

                        // met a jour donnees a partir chaine recue
                        g.updateOptions( { ‘file’: stringDataIn } ); // met a jour les donnees du graphique

                        // recupere derniere valeur
                        textInputDygraphs.value=Number(g.getValue(0,g.numColumns()-1) ); // derniere valeur du graphique
                        // voir : http://dygraphs.com/jsdoc/symbols/Dygraph.html

                        //setTimeout(function () {requeteAjax(manageReponseAjax);}, delai); // relance delai avant nouvelle requete Ajax

                } // fin fonction gestion de la reponse Ajax

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

    </head>

    <body>  

    <div id= »graphdiv »></div>
        <br/>
        Valeur courante = <input type= »text » id= »valeurDygraphs » />

        <br/>

                <select  style= »width: 300px » id= »liste » >
«  » »
+

optionsFiles

+
«  » »
                </select>

                <br/>

        <textarea id= »text » rows= »15″ cols= »100″></textarea>

        </body>

</html>
«  » »

)  # fin page HTML+JS initiale
        return contenuPageInitialeHTMLJS # la fonction renvoie la page HTML

#===================== Reponse AJAX ==================

#— fonction fournissant la page de reponse AJAX
def reponseAJAX(indexIn):

        # definition des variables a uiliser dans la reponse
        global files

        dirPath=homePath()+« data/text/ »
        filename=files[indexIn]
        filepath=dirPath+filename

        print filepath

        #– lecture du fichier — pour debug
        myFile=open(filepath,‘r’) # ouverture en lecture
        print (« Contenu du fichier : « )
        myFile.seek(0) # se met au debut du fichier
        fileContent= myFile.read() # lit le fichier
        print fileContent

        myFile.close() # fermeture du fichier

        # attention – ici le formatage est la chaîne brute, pas la chaîne au sein de code JS.. subtil.. !
        # donc en fait ici, on peut envoyer le contenu du fichier as is

        # la reponse
        reponseAjax=( # debut page reponse AJAX

        #filename # renvoie le nom du fichier
        #+ »\n »
        #+
        fileContent  # contenu du fichier

)  # fin page reponse AJAX
        return reponseAjax# la fonction renvoie la page HTML

#— obligatoire pour lancement du code —
if __name__==« __main__ »: # pour rendre le code executable
        setup() # appelle la fonction setup
        while not noLoop: loop() # appelle fonction loop sans fin

 

Ce code est également disponible ici : https://raw.github.com/sensor56/pyduino-exemples/master/Ethernet/EthernetServerHTMLJSAjaxSelectFilesDygraphsxn.py

Utilisation

  • Connecter le mini-PC au réseau
  • Appuyer sur le bouton exécuter dans Geany
  • Une fenêtre de Terminal doit apparaître : un message indique que le serveur attend un client entrant.
  • Ouvrir alors sur le poste client un navigateur, par exemple firefox, et saisir l’adresse ip du mini-PC suivie de :8080 ce qui donne par exemple 192.168.1.13:8080. On utilise ici le port 8080 d’où le :8080…
  • A ce moment là, on doit voir sur le mini-PC les messages attestant de la connexion du client ainsi que le requête reçue
  • Puis le serveur envoie sa réponse intégrant l’entête http et la page HTML
  • Du côté client, la page HTML doit s’afficher :
    • une liste déroulante permet de sélectionner le fichier voulu,
    • ici, les données reçue en réponse à la requête Ajax met à jour le graphique Dygraphs sans recharger la page complète. Ici, le contenu du fichier est affiché sous forme graphique.
  • Il est possible également d’éditer le source de la page permettant de s’assurer que le code HTML + javascript envoyé par le code pyduino est correct
  • Noter que le poste fixe peut simultanément accéder au mini-PC par VNC (qui utilise le port 5900) et par le navigateur client ( qui utilise le port 8080) !

Discussion technique

  • Une interface souple d’emploi qui permettra de visualiser plusieurs fichiers de données simplement.

Donnez votre avis

Soyez le 1er à noter cet article
ou bien laissez un avis détaillé


Partagez cet article maintenant !


Ça ne règle pas votre cas ?

Décrivez la panne sur le forum, avec une photo si vous pouvez : les membres qui ont eu la même répondent, et le sujet reste pour les suivants.

Avatar photoAvatar photoAvatar photoAvatar photoAvatar photoRejoindre les 54 membres — gratuit, 44 pannes résolues

Dans le même tiroir

Shield Kit EasyCard par EasyRobotics
Électronique

Shield Kit EasyCard par EasyRobotics

Le Shield Kit EasyCard par EasyRobotics est une solution innovante pour les développeurs et les ingénieurs qui souhaitent créer des…

Portrait de Inès DameronInès Dameron · 22 Avr 2023

Réagissez à cet article

La lettre du club

Une lettre par mois, accrochée au panneau

Les sujets du forum résolus dans le mois, un guide, un chiffre qu’on peut vérifier chez soi. Rien d’autre, jamais plus souvent — et on se désabonne d’un clic.

Ce qu’il y a dedans

Votre adresse

Une lettre par mois. Désabonnement en un clic.

Partagez votre réaction