IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Arduino Discussion :

AsyncWebServer - Amélioration du code C/C++


Sujet :

Arduino

  1. #1
    Membre habitué
    Homme Profil pro
    bricoleur
    Inscrit en
    Octobre 2014
    Messages
    344
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : bricoleur
    Secteur : Alimentation

    Informations forums :
    Inscription : Octobre 2014
    Messages : 344
    Points : 175
    Points
    175
    Par défaut AsyncWebServer - Amélioration du code C/C++
    Bonjour à tous,
    J'ai pratiquement terminé le développement d'un projet de domotique sur ESP32 et j'en suis au stade des améliorations dans le but d'optimiser le code. La partie suivante est, sans aucun doute, mal foutue!
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    serveur.on("/API", HTTP_GET, [](AsyncWebServerRequest *req){
        if(!clientConnected){
          req->send(408,"text/html", "Timeout");
          return;
        }
        String reponse = "" , equipement= "", taux = "";
        String commande[8], action[8];
        int nbArgs = req->args();
        for(int i=0;i<nbArgs;i++){
          commande[i] = req->argName(i);
          action[i]=req->arg(i);
        }
        //modification d'un programme horaire
        if(commande[0] == "Cmd" && action[0]=="modif"){
          uint8_t prg = action[1].toInt();
          reponse= String(pg[prg]);
          req->send(200,"text/plain", reponse);
        }
        //demande ouverture volet
        else if( commande[0] == "Cmd"  && action[0] == "O" && commande[1] == "volet") {
          equipement = req->arg(1);
          taux = req->arg(2);
          reponse = "Ok" + equipement + "O" + taux;
          req->send(200,"text/plain", reponse);
          if(taux=="100") taux="00";
          cmdCl[0]= 'O'; cmdCl[1]= equipement.charAt(0); cmdCl[2]= taux.charAt(0); cmdCl[3]=taux.charAt(1);
          cmdCl[4]='Z'; cmdCl[5]='\0';
          commandeRecu=true;
        }
        //demande fermeture volet
        else if(commande[0] == "Cmd" && action[0] == "F" && commande[1] == "volet" ){
          equipement = req->arg(1);
          reponse = "Ok"+ equipement + "F" + "00";
          req->send(200,"text/plain", reponse);
          cmdCl[0]= 'F'; cmdCl[1]= equipement.charAt(0); cmdCl[2]= 'Z'; cmdCl[3]='\0';
          commandeRecu=true;
        }
        //demande etat volet(s)
        else if(commande[0] == "Cmd" && action[0] == "E" && commande[1] == "volet" ){
          //E=Cmd Etat & commande[1] carte=arg[1]=A (c'est un volet) & commande[2] valeur=arg[2]=adresse carte 
          equipement = req->arg(2);
          String tempo = "";
          if(equipement != "0"){    //****un seul volet****
            uint8_t etatduVolet = etatVol[equipement.toInt() -1];
            if(etatduVolet == 0){
              reponse = "Ok" + equipement + "00"; //en fermeture totale
            }
            else{
              tempo = (etatduVolet == 100)? "OT" : String(etatduVolet-100);
              reponse = "Ok" + equipement +  tempo;
            }
            req->send(200,"text/plain", reponse);
          }
          else{                 //****tous les volets****
            reponse = "Ok";
            for(i=0; i<NB_VOLETS; i++){
              if(etatVol[i]== 0) tempo = "00";
              else if(etatVol[i]==100) tempo="OT";
              else tempo= String(etatVol[i]-100);
              reponse += tempo;
            }
            req->send(200,"text/plain",reponse);
          }
        }
         .............
       }
    Et ainsi de suite, avec une vingtaine de commandes.
    Est-il possible de supprimer les "String"?
    Puis-je écrire une API simple qui appellerait une procédure d'analyse en passant en argument les tableaux commande[] et action[], un peu comme cela:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    serveur.on("/API", HTTP_GET, [](AsyncWebServerRequest *req){
        if(!clientConnected){
          req->send(408,"text/html", "Timeout");
          return;
        }
        String reponse = "" , equipement= "", taux = "";
        String commande[8], action[8];
        int nbArgs = req->args();
        for(int i=0;i<nbArgs;i++){
          commande[i] = req->argName(i);
          action[i]=req->arg(i);
        }
         analyseCommandes(commande,action);
      }
    Je dois avouer que je me mélange encore les pinceaux avec les pointeurs.
    Un peu d'aide me serait bénéfique.

  2. #2
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 804
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 804
    Points : 5 655
    Points
    5 655
    Par défaut
    oui vous pouvez bien sûr passer par une fonction mais elle ne ferait que faire que ce que votre code fait déjà...

    Pour moi la question est plutôt de savoir pourquoi vous dupliquez les éléments req->argName et req->arg dans vos tableaux - ce sont déjà des String.

    au lieu de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
      if (commande[0] == "Cmd" && action[0] == "modif") {
        uint8_t prg = action[1].toInt();
        reponse = String(pg[prg]);
        req->send(200, "text/plain", reponse);
      }
    vous pourriez très bien faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
      if (req->argName(0)== "Cmd" && req->arg(0)== "modif") {
        uint8_t prg =req->arg(1).toInt();
        reponse = pg[prg];
        req->send(200, "text/plain", reponse);
      }
    PS: Le code manque de tests de sécurité - par exemple que se passe-t-il si j'envoie une requête /API avec 10 paramètres (vous débordez de votre tableau) ou juste "Cmd" sans remplir le reste (vous utilisez les éléments du tableau sans savoir s'ils ont été remplis et donc ça pointe n'importe où en mémoire).

  3. #3
    Membre habitué
    Homme Profil pro
    bricoleur
    Inscrit en
    Octobre 2014
    Messages
    344
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : bricoleur
    Secteur : Alimentation

    Informations forums :
    Inscription : Octobre 2014
    Messages : 344
    Points : 175
    Points
    175
    Par défaut
    reponse = pg[prg];
    le tableau pg est défini ainsi:
    'reponse' étant un 'String' il faut bien que je le 'caste'.

    Mais ma question ne porte pas pour l'instant sur les différentes commandes (qui méritent j'en convient quelques corrections)
    plutôt sur le fait qu'il me semble qu'à l'initialisation du serveur, il y a une grosse quantité d'informations passée en valeur alors
    qu'avec une procédure et des pointeurs cela sera plus efficace?

  4. #4
    Membre expérimenté
    Femme Profil pro
    ..
    Inscrit en
    Décembre 2019
    Messages
    652
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 94
    Localisation : Autre

    Informations professionnelles :
    Activité : ..

    Informations forums :
    Inscription : Décembre 2019
    Messages : 652
    Points : 1 428
    Points
    1 428
    Par défaut
    Salut,

    Pour faire plus simple, tu peux t'orienter vers une fonction libre pour fonction de rappel :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void dispatch_request(async_web_server_requrest* request) 
    {
        ...
    }
    .../...
    server.on("/api", http_get, dispatch_request);
    Sinon, il n'y a pas de lib RPC (remote procedure call; conf. wikipedia) pour ton ESP ?

  5. #5
    Membre habitué
    Homme Profil pro
    bricoleur
    Inscrit en
    Octobre 2014
    Messages
    344
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : bricoleur
    Secteur : Alimentation

    Informations forums :
    Inscription : Octobre 2014
    Messages : 344
    Points : 175
    Points
    175
    Par défaut
    PS: Le code manque de tests de sécurité
    En fait j'ai traité ces problèmes côté client: les messages reçus ne peuvent pas être formattés de façon incorrecte; mais peut-être n'est-ce pas une bonne pratique?

    une fonction libre pour fonction de rappel
    Désolé je ne sais pas ce que c'est. Et l'exemple ne me cause pas.

    Je crois que s'il n'y a pas moyen d'améliorer ce code, puisqu'il fonctionne, je vais continuer ainsi.

    Merci de votre aide.

  6. #6
    Membre expérimenté
    Femme Profil pro
    ..
    Inscrit en
    Décembre 2019
    Messages
    652
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 94
    Localisation : Autre

    Informations professionnelles :
    Activité : ..

    Informations forums :
    Inscription : Décembre 2019
    Messages : 652
    Points : 1 428
    Points
    1 428
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    void analyseRequest(AsyncWebServerRequest* req);
     
    void setup()
    {
        server.on("/API", HTTP_GET, analyseRequest);
    }
     
    void analyseRequest(AsyncWebServerRequest* req)
    {
        //faire ce que tu veux de req...
        //req->args() 
    }
    Est-ce plus clair ?

  7. #7
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 804
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 804
    Points : 5 655
    Points
    5 655
    Par défaut
    Citation Envoyé par mormic Voir le message
    le tableau pg est défini ainsi:
    'reponse' étant un 'String' il faut bien que je le 'caste'.
    quand on affecte une cstring à une String, la conversion est automatique
    vous pouvez essayer cela pour vous en convaincre:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    char bonjours[10][81] = {
      "Bonjour !",  "Salut !",  "Coucou !",
      "Hello !",  "Bon matin !",  "Bonne journée !",
      "Saaaaalut toi !",  "Hey !",  "Coucou toi !",
      "Bonjour à tous !"
    };
     
    void setup() {
      String test;
      Serial.begin(115200);
      for (byte i = 0; i < 10; i++) {
        test = bonjours[i];
        Serial.println(test);
      }
    }
     
    void loop() {}



    En fait j'ai traité ces problèmes côté client: les messages reçus ne peuvent pas être formattés de façon incorrecte; mais peut-être n'est-ce pas une bonne pratique?
    disons que ce n'est pas dans les meilleures pratiques

    - si vous avez une erreur de transmission ça peut planter votre serveur
    - si vous étes sur un réseau public, on peut vous attaquer pour faire planter votre serveur

    peut être que dans votre environnement domestique ce n'est pas un drame





    Je crois que s'il n'y a pas moyen d'améliorer ce code, puisqu'il fonctionne, je vais continuer ainsi
    Ne gâchez pas de la mémoire, réutilisez directement les champs extraits par la bibliothèque

  8. #8
    Membre habitué
    Homme Profil pro
    bricoleur
    Inscrit en
    Octobre 2014
    Messages
    344
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : bricoleur
    Secteur : Alimentation

    Informations forums :
    Inscription : Octobre 2014
    Messages : 344
    Points : 175
    Points
    175
    Par défaut
    Bien, merci pour ces informations.
    Je digère tout cela et je continue.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. De la rapidité du code
    Par jfloviou dans le forum Contribuez
    Réponses: 233
    Dernier message: 29/05/2009, 02h17
  2. code pour interbase 6.0 et 6.5 de generateur
    Par tripper.dim dans le forum InterBase
    Réponses: 4
    Dernier message: 01/07/2002, 11h29
  3. [MFC](encapsulation ADO) ou placer le code
    Par philippe V dans le forum MFC
    Réponses: 2
    Dernier message: 13/06/2002, 14h58
  4. Explorateur de code C
    Par Zero dans le forum C
    Réponses: 14
    Dernier message: 06/06/2002, 09h41
  5. OmniORB : code sous Windows et Linux
    Par debug dans le forum CORBA
    Réponses: 2
    Dernier message: 30/04/2002, 17h45

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo