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:
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.// 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);
}
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:
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 coolvar 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"];
}
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 ?
-----