[Programmation] Perte du serveur de mon Shield Ethernet pour Arduino
Répondre à la discussion
Affichage des résultats 1 à 14 sur 14

Perte du serveur de mon Shield Ethernet pour Arduino



  1. #1
    Atroverso

    Perte du serveur de mon Shield Ethernet pour Arduino


    ------

    Bonjour à tous, meilleurs vœux et un tas de projets rondement menés pour cette nouvelle année !

    Je vous expose mon problème:

    Je me suis lancé récemment dans le pilotage de ma carte Uno d'Arduino depuis l'extérieur grâce au Shield Ethernet.

    J'ai utilisé l'exemple du site d'Eskimon:

    // Ces deux bibliothèques sont indispensables pour le shield
    #include <SPI.h>
    #include <Ethernet.h>

    // L'adresse MAC du shield
    byte mac[] = { 0x90, 0xA2, 0xDA, 0x0E, 0xA5, 0x7E };
    // L'adresse IP que prendra le shield
    IPAddress ip(192,168,0,143);

    // Initialise notre serveur
    // Ce dernier écoutera sur le port 4200
    EthernetServer serveur(4200);

    char *url = (char *)malloc(100); // L'url recu à stocker
    //char url[100];
    char index = 0; // index indiquant où l'on est rendu dans la chaîne
    boolean etats[3] = {LOW, LOW, LOW}; // L'état des 3 sorties
    unsigned char pwm = 0; // La valeur de la pwm

    void setup()
    {
    // On démarre la voie série pour déboguer
    Serial.begin(9600);

    // Configure et initialise les broches
    pinMode(3, OUTPUT); digitalWrite(3, LOW);
    pinMode(4, OUTPUT); digitalWrite(4, LOW);
    pinMode(5, OUTPUT); digitalWrite(5, LOW);
    pinMode(6, OUTPUT); analogWrite(6, 0);

    char erreur = 0;
    // On démarre le shield Ethernet SANS adresse ip (donc donnée via DHCP)
    erreur = Ethernet.begin(mac);

    if (erreur == 0) {
    Serial.println("Parametrage avec ip fixe...");
    // si une erreur a eu lieu cela signifie que l'attribution DHCP
    // ne fonctionne pas. On initialise donc en forçant une IP
    Ethernet.begin(mac, ip);
    }
    Serial.println("Init...");
    // Donne une seconde au shield pour s'initialiser
    delay(1000);
    // On lance le serveur
    serveur.begin();
    Serial.println("Pret !");
    }

    void loop() {
    // Regarde si un client est connecté et attend une réponse
    EthernetClient client = serveur.available();
    if (client) { // Un client est là ?
    Serial.println("Ping !");
    url = ""; // on remet à zéro notre chaîne tampon
    index = 0;
    while(client.connected()) { // Tant que le client est connecté
    if(client.available()) { // A-t-il des choses à dire ?
    // traitement des infos du client
    char carlu = client.read(); //on lit ce qu'il raconte
    if(carlu != '\n') { // On est en fin de chaîne ?
    // non ! alors on stocke le caractère
    Serial.print(carlu);
    url[index] = carlu;
    index++;
    } else {
    // on a fini de lire ce qui nous interesse
    // on marque la fin de l'url (caractère de fin de chaîne)
    url[index] = '';
    boolean ok = interpreter(); // essaie d'interpreter la chaîne
    if(ok) {
    // tout s'est bien passé = on met à jour les broches
    action();
    }
    // et dans tout les cas on répond au client
    repondre(client);
    // on quitte le while
    break;
    }
    }
    }
    // Donne le temps au client de prendre les données
    delay(10);
    // Ferme la connexion avec le client
    client.stop();
    Serial.println("Pong !");
    }
    }

    void rafraichir() {
    // Rafraichit l'etat des broches / PWM
    digitalWrite(3, etats[0]);
    digitalWrite(4, etats[1]);
    digitalWrite(5, etats[2]);
    analogWrite(6, pwm);
    }

    void repondre(EthernetClient client) {
    // La fonction prend un client en argument

    Serial.println("\nRepondre"); // debug
    // On fait notre en-tête
    // Tout d'abord le code de réponse 200 = réussite
    client.println("HTTP/1.1 200 OK");
    // Puis le type mime du contenu renvoyé, du json
    client.println("Content-Type: application/json");
    // Autorise le cross origin
    client.println("Access-Control-Allow-Origin: *");
    // Et c'est tout !
    // On envoi une ligne vide pour signaler la fin du header
    client.println();

    // Puis on commence notre JSON par une accolade ouvrante
    client.println("{");
    // On envoie la première clé : "uptime"
    client.print("\t\"uptime\": ");
    // Puis la valeur de l'uptime
    client.print(millis());
    //Une petite virgule pour séparer les deux clés
    client.println(",");
    // Et on envoie la seconde nommée "analog 0"
    client.print("\t\"A0\": ");
    client.print(analogRead(A0));
    client.println(",");
    // Puis la valeur de la PWM sur la broche 6
    client.print("\t\"pwm\": ");
    client.print(pwm, DEC);
    client.println(",");
    // Dernières valeurs, les broches (elles mêmes dans un tableau)
    client.println("\t\"broches\": {");
    // La broche 3
    client.print("\t\t\"3\": ");
    client.print(digitalRead(3));
    client.println(",");
    // La broche 4
    client.print("\t\t\"4\": ");
    client.print(digitalRead(4));
    client.println(",");
    // La broche 5
    client.print("\t\t\"5\": ");
    client.println(digitalRead(5)) ;
    client.println("\t}");
    // Et enfin on termine notre JSON par une accolade fermante
    client.println("}");
    }

    boolean interpreter() {
    // On commence par mettre à zéro tous les états
    etats[0] = LOW;
    etats[1] = LOW;
    etats[2] = LOW;
    pwm = 0;

    // Puis maintenant on va chercher les caractères/marqueurs un par un.
    index = 0; // Index pour se promener dans la chaîne (commence à 4 pour enlever "GET "
    while(url[index-1] != 'b' && url[index] != '=') { // On commence par chercher le "b="
    index++; // Passe au caractère suivant
    if(index == 100) {
    // On est rendu trop loin !
    Serial.println("Oups, probleme dans la recherche de 'b='");
    return false;
    }
    }
    // Puis on lit jusqu’à trouver le '&' séparant les broches de pwm
    while(url[index] != '&') { // On cherche le '&'
    if(url[index] >= '3' && url[index] <= '5') {
    // On a trouvé un chiffre identifiant une broche
    char broche = url[index]-'0'; // On ramène ça au format décimal
    etats[broche-3] = HIGH; // Puis on met la broche dans un futur état haut
    }
    index++; // Passe au caractère suivant
    if(index == 100) {
    // On est rendu trop loin !
    Serial.println("Oups, probleme dans la lecture des broches");
    return false;
    }
    // NOTE : Les virgules séparatrices sont ignorées
    }
    // On a les broches, reste plus que la valeur de la PWM
    // On cherche le "p="
    while(url[index-1] != 'p' && url[index] != '=' && index= '0' && url[index] <= '9') {
    // On a trouvé un chiffre !
    char val = url[index]-'0'; // On ramène ça au format décimal
    pwm = (pwm*10) + val; // On stocke dans la pwm
    }
    index++; // Passe au caractère suivant
    if(index == 100) {
    // On est rendu trop loin !
    Serial.println("Oups, probleme dans la lecture de la pwm");
    return false;
    }
    // NOTE : Les virgules séparatrices sont ignorées
    }
    // Rendu ici, on a trouvé toutes les informations utiles !
    return true;
    }

    void action() {
    // On met à jour nos broches
    digitalWrite(3, etats[0]);
    digitalWrite(4, etats[1]);
    digitalWrite(5, etats[2]);
    // Et la PWM
    analogWrite(6, pwm);
    }
    Premier fait étrange, je n'arrive pas aucun moyen a obtenir l'IP fixe qui est définie dans le code. J'ai beau déconnecter le câble Ethernet ou désactiver le DHCP de ma BBox (la dernière) de Bouygues, rien n'y fait.

    Mais bon, quand je branche tout j'obtiens donc une adresse locale pour mon Shield tirée depuis l'adresse MAC correspondante définie dans les paramètres de ma Bbox.
    Admettons que l'IP attribuée soit donc 192.168.1.90, j'effectue la redirection de port depuis l'extérieur (inclus dans mon code HTML).

    Je branche une petite LED blanche sur la broche 5 pour faire joujou grâce à cette page HTML que j'ouvre avec mon smartphone depuis le réseau de data mobile:

    var broches = []; // Tableau de broches
    var etats = []; // Tableau d'etat des broches
    var pwm;
    var a0;
    var millis;
    var adresse = "http://176.178.60.197:4200/"; // L'url+port de votre shield

    document.addEventListener('DOM ContentLoaded', setup, false);

    function setup() {
    // fonction qui va lier les variables a leur conteneur html
    broches[3] = document.getElementById("broch e3");
    broches[4] = document.getElementById("broch e4");
    broches[5] = document.getElementById("broch e5");
    etats[3] = document.getElementById("etat3 ");
    etats[4] = document.getElementById("etat4 ");
    etats[5] = document.getElementById("etat5 ");
    pwm = document.getElementById("pwm") ;
    a0 = document.getElementById("a0");
    millis = document.getElementById("milli s");

    // La fonction concernant le bouton
    var bouton = document.getElementById("envoy er");
    bouton.addEventListener('click ', executer, false);
    }

    Qui me donne ça: Interface HTML

    Jusque là, quand je m'y connecte, j'obtiens


    function executer() {
    // Fonction qui va créer l'url avec les paramètres puis
    // envoyer la requête
    var requete = new XMLHttpRequest(); // créer un objet de requête
    var url = adresse;
    url += "?b=";
    for(i=3; i <= 5; i++) { // Pour les broches 3 à 5 de notre tableau
    if(broches[i].checked) // si la case est cochée
    url += i + ",";
    }
    // enlève la dernière virgule si elle existe
    if(url[url.length-1] === ',')
    url = url.substring(0, url.length-1);
    // Puis on ajoute la pwm
    url += "&p=" + pwm.value;
    console.log(url) // Pour debugguer l'url formée
    requete.open("GET", url, true); // On construit la requête
    requete.send(null); // On envoie !
    requete.onreadystatechange = function() { // on attend le retour
    if (requete.readyState == 4) { // Revenu !
    if (requete.status == 200) {// Retour s'est bien passé !
    // fonction d'affichage (ci-dessous)
    afficher(requete.responseText) ;
    } else { // Retour s'est mal passé
    alert(requete.status, requete.statusText);
    }
    }
    };
    }

    function afficher(json) {
    // Affiche l'état des broches/pwm/millis revenu en json
    donnees = JSON.parse(json);
    console.log(donnees);

    for(i=3; i <= 5; i++) { // Pour les broches 3 à 5 de notre tableau
    etats[i].checked = donnees["broches"][i];
    }
    pwm.value = parseInt(donnees["pwm"]);
    a0.value = parseInt(donnees["A0"]);
    millis.textContent = donnees["uptime"];
    }
    Et miracle, ça fonctionne ! Quand je coche broche 5 et que je fais Executer sur la page HTML, la LED s'allume et l'uptime (Millis) se met à jour, je décoche et je renvoie et elle s'éteint ! Trop cool

    Cependant, au bout de quelques envois, le serveur "plante", à savoir que la page ne se recharge plus et le serveur est injoignable. J'ai fait alors des tests pour voir l'adresse IP du Shield en cours de route et quand le serveur plante, il n'obtient plus l'adresse dédiée (192.168.1.90) mais une adresse du masque réseau: 255.255.255.255 et toujours celle-ci. Peu importe si je RESET le Shield Ethernet, la carte, rebranche le câble Ethernet !

    Le seul moyen est de couper complètement l'alim de la carte Uno et de la rebrancher. L'adresse IP redevient 192.168.1.90.

    Donc je ne comprends pas cet aléa, des fois je peux piloter la LED 10 fois sans problème, des fois la première utilisation fait planter mon serveur ! Et cela que je pilote depuis la data mobile comme depuis le PC en accès local...

    Est-ce que quelqu'un aurait une piste ?

    -----

  2. #2
    nornand

    Re : Perte du serveur de mon Shield Ethernet pour Arduino

    bjr, ton masque de sous réseau devrait être "masque 255.255.255.0" non ?

  3. #3
    Atroverso

    Re : Perte du serveur de mon Shield Ethernet pour Arduino

    Oui mon masque de fini bien en zéro mais le localIP du Shield renvoie 255 à la fin aussi

    Je ne comprends vraiment pas cette logique
    Et le thread semble bloqué

  4. #4
    Ikhar84
    Animateur Informatique

    Re : Perte du serveur de mon Shield Ethernet pour Arduino

    L'IP privée de la bbox est 192.168.1.254 avec un masque en 255.255.255.0

    Donc les IP possible du réseau vont de 192.168.1.1 à 192.168.1.253
    (La première est déconseillée, et il faut vérifier dans l'interface d'admin de la box que l'IP choisie est libre...)
    192.168.1.0 et 192.168.1.255 sont de IP spéciales.

    Pourquoi dans ton code tu utilises ces adresses IP:
    Code:
    // L'adresse IP que prendra le shield
    IPAddress ip(192,168,0,143);
    
    var adresse = "http://176.178.60.197:4200/";  // L'url+port de votre shield
    Pourquoi ne pas mettre directement 192.168.1.90 en dur dans le code ?

    Voici une rapide adaptation depuis le tuto du ChatServer d'arduino (reste à adapter ton @ mac...).
    Code:
    #include <Ethernet.h>
    
    // Enter a MAC address and IP address for your controller below.
    // The IP address will be dependent on your local network.
    // gateway and subnet are optional:
    byte mac[] = {
      0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
    };
    IPAddress ip(192, 168, 1, 90);
    IPAddress myDns(192,168,1, 254);
    IPAddress gateway(192, 168, 1, 254);
    IPAddress subnet(255, 255, 255, 0);
    
    // port
    EthernetServer server(4200);
    
    void setup() {
      // initialize the ethernet device
      Ethernet.begin(mac, ip, myDns, gateway, subnet);
      // start listening for clients
      server.begin();
    
      Serial.println(Ethernet.localIP());
    }
    Dernière modification par Ikhar84 ; 09/01/2018 à 15h57.
    J'ai glissé Chef !

  5. A voir en vidéo sur Futura
  6. #5
    Atroverso

    Re : Perte du serveur de mon Shield Ethernet pour Arduino

    Et bien si je mets 192.168.xx.xx dans le code, ça me donne une IP locale non ?
    Celle qu'il y a actuellement correspond mon IP publique suivi du port du redirection.

    J'essai ton code ce soir pour voir.

  7. #6
    USMC

    Re : Perte du serveur de mon Shield Ethernet pour Arduino

    Normalement tu n'as pas besoin de faire figurer ton adresse IP publique dans le code.
    La redirection est faite sur la box, par exemple : 173.20.20.20:4200 => 192.168.1.90:4200
    L'arduino s'en fout normalement.

    Du coup dans le navigateur de ton téléphone, tu tape en url 173.20.20.20:4200 et tu aura accès à ton interface web.
    D'ailleurs, mettre ton IP publique sur le web comme ça c'est pas top.

  8. #7
    Atroverso

    Re : Perte du serveur de mon Shield Ethernet pour Arduino

    En fait, tu pourras remarquer que l'adresse en haut est bidon, c'est juste du texte:

    Adresse publique du shield : <br /> http://<input type="text" id="ip" value="123.123.123.123" size="15"/>


    Par contre, en dur dans le code c'est bien là que le fichier HTML qui est sur mon Bureau m'emmène d'un clic, donc ça me permet de ne justement pas avoir à le taper, simplement l'ouvrir.

    var adresse = "http://176.178.60.197:4200/"; // L'url+port de votre shield

    Et ne t'inquiète pas, ce n'est pas mon IP perso, c'est juste ressemblant mais tout est bidon ^^

  9. #8
    Ikhar84
    Animateur Informatique

    Re : Perte du serveur de mon Shield Ethernet pour Arduino

    Citation Envoyé par USMC Voir le message
    Normalement tu n'as pas besoin de faire figurer ton adresse IP publique dans le code.
    La redirection est faite sur la box, par exemple : 173.20.20.20:4200 => 192.168.1.90:4200
    L'arduino s'en fout normalement.

    Du coup dans le navigateur de ton téléphone, tu tape en url 173.20.20.20:4200 et tu aura accès à ton interface web.
    D'ailleurs, mettre ton IP publique sur le web comme ça c'est pas top.
    C'est exactement ça, le serveur ne connait pas et n'a pas à connaitre l'IP publique à partir de laquelle se connecte son client, il lui suffit de connaitre son IP privée (locale) pour savoir que c'est à lui que l'on s'adresse (et le port pour transmettre les données au bon "logiciel").

    Par contre, de l'exterieur, tu appelles bien to IP publique.

    La traduction IP publique/IP privée (et l'inverse) est le boulot de la box (via le nat notamment), c'est d'ailleurs pour cela qu'il faut un IP privée statique et non pas dynamique, pour retrouver le serveur dans le réseau local.
    Edit: traduction = pas de DHCP...
    J'ai glissé Chef !

  10. #9
    Atroverso

    Re : Perte du serveur de mon Shield Ethernet pour Arduino

    Je ne comprends absolument pas ce que vous essayez de m'expliquer tous les deux !

    Comment une page HTML peut elle envoyer mes ordres si je ne lui donne pas l'adresse fixe de ma box + le port de redirection qui va ensuite amener mes ordres vers l'adresse locale + port d'écoute ?

  11. #10
    Ikhar84
    Animateur Informatique

    Re : Perte du serveur de mon Shield Ethernet pour Arduino

    Ok...
    Tes posts n'étaient vraiment pas clair, après avoir (vite) lu la page du tuto que tu as donné:

    Il ne faut pas mélanger le code de ta page HTML/javascript avec le code arduino...

    Code:
    var adresse = "http://176.178.60.197:4200/"; // L'url+port de votre shield
    Là, dans ton fichier html, tu mets ton IP publique, ainsi que le port que tu as ouvert su ta bbox...

    Le code que j'ai donné plus haut, lui, est pour initialisé la connexion sur l'arduino, qui lui ne connaît que l'IP privée:
    Code:
    #include <Ethernet.h>
    
    // Enter a MAC address and IP address for your controller below.
    // The IP address will be dependent on your local network.
    // gateway and subnet are optional:
    byte mac[] = {
      0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
    };
    IPAddress ip(192, 168, 1, 90);
    IPAddress myDns(192,168,1, 254);
    IPAddress gateway(192, 168, 1, 254);
    IPAddress subnet(255, 255, 255, 0);
    
    // port
    EthernetServer server(4200);
    
    void setup() {
      // initialize the ethernet device
      Ethernet.begin(mac, ip, myDns, gateway, subnet);
      // start listening for clients
      server.begin();
    
      Serial.println(Ethernet.localIP());
    }
    En n'oubliant pas d'adapter ton adresse mac...
    J'ai glissé Chef !

  12. #11
    USMC

    Re : Perte du serveur de mon Shield Ethernet pour Arduino

    En fait, je pense que c'est le code du site Eskimon qui complique l'affaire.
    Tu devrais essayer de trouver d'autres exemples pour voir si le problème est reproductible avec ton matériel.

    Dans une logique générale ça marche comme ça :
    - Une redirection de port est en place sur la box ou un pare-feu (173.20.20.20:4200 => 192.168.1.90:4200)
    - Le client sollicite l'adresse 173.20.20.20:4200 dans son navigateur, le serveur répond au client et la page s'affiche dans le navigateur

    La box garde une liste de sessions actives pendant x temps pour que le serveur soit en mesure de répondre au client.
    Toutes les requêtes (un clic sur un bouton, etc) sont envoyées à l'adresse IP publique+port adéquat et la box se charge de gérer la communication.

    Pour ce qui est du DHCP, tu risques d'obtenir une adresse IP différente à chaque demande de bail. Donc soit tu te mets en IP fixe soit tu fais une réservation sur la box avec la MAC de l'arduino.
    J'espère que tu y vois plus claire.

  13. #12
    Atroverso

    Re : Perte du serveur de mon Shield Ethernet pour Arduino

    Oui j'ai bien reservé l'adresse IP pour l'adresse MAC de mon Arduino, pas de souci, il est toujours sur cette adresse quand il fonctionne d'ailleurs.

    Je pensais que j'avais été clair en disant que j'utilise un fichier HTML pour me connecté. Et d'ailleurs je ne vois pas le souci de sécurité puisque ce fichier HTML n'est présent que sur mes appareils, donc mon IP publique n'est que dans le code de CES fichiers présents uniquement sur MES appareils (PC, Smartphone). De lus, je le répète, les adresse utilisées dans mes posts sont BIDONS ! C'est juste pour être plus précis que des xx.xx.xx.xx

    Donc oui j'ai un fichier html+javascript et l'arduino avec son code à côté, mais bon, rien qu'aux langages ou balises il est difficile de s'y tromper !

    Le code d'Eskimon est peut-être trop complexe et possède une partie instable mais bon, ça m'étonnerait quand même vu tous les commentaires positifs qu'il a sur son site à propos de ce code.

    Je te rejoins USMC sur cette piste: une histoire de bail.
    Bien que je ne comprends pas où ça cloche car des fois je peux spammer mes broches ON/OFF 10 fois d'affilée en 1min, une fois toutes les 30min et ça fonctionne, et la fois suivante c'est l'inverse avec les mêmes intervalles.
    Mon Arduino redéclare avoir une IP en 255.255.255.255 quand je lui dis de me donner sa local IP, ça n'a aucun sens o_O

  14. #13
    USMC

    Re : Perte du serveur de mon Shield Ethernet pour Arduino

    Tu utilises les produits officiel Arduino ou des clones chinois ?

  15. #14
    Atroverso

    Re : Perte du serveur de mon Shield Ethernet pour Arduino

    Clone, mais je dois avoir la Uno officielle qui traine quelque part pour tester bien que le problème viendrait plutôt du Shield :/

Discussions similaires

  1. [Programmation] ARDUINO Ethernet shield (client)
    Par electron44 dans le forum Électronique
    Réponses: 8
    Dernier message: 14/06/2016, 14h26
  2. [Analogique] [projet] shield arduino pour lire des capteurs de force
    Par jjehl dans le forum Électronique
    Réponses: 23
    Dernier message: 01/03/2016, 20h09
  3. Quel shield Bluetooth pour mon Arduino Uno?
    Par benbosch dans le forum Électronique
    Réponses: 12
    Dernier message: 11/05/2015, 07h17
  4. Shield port Ethernet
    Par achampion dans le forum Électronique
    Réponses: 1
    Dernier message: 01/04/2015, 05h59
  5. Ethernet Shield arduino
    Par lm321 dans le forum Électronique
    Réponses: 1
    Dernier message: 24/11/2014, 08h20
Découvrez nos comparatifs produits sur l'informatique et les technologies.