// --- Inclusion des librairies ---
#include <SPI.h> // librairie SPI - obligatoire avec librairie Ethernet
#include <Ethernet.h> // librairie Ethernet
// --- Déclaration des constantes ---
const int LED=3; // broche utilisée pour la LED
int etatLED=LOW; // reflet état de la LED - étente au départ
// --- Déclaration des variables globales ---
//--- l'adresse mac = identifiant unique du shield
// à fixer arbitrairement ou en utilisant l'adresse imprimée sur l'étiquette du shield
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0F, 0x53, 0xDD };
//----- l'adresse IP fixe à utiliser pour le shield Ethernet ---
IPAddress ipLocal(172, 18, 68, 122); // l'adresse IP locale du shield Ethernet
// ATTENTION : il faut utiliser une adresse hors de la plage d'adresses du routeur DHCP
// pour connaitre la plage d'adresse du routeur : s'y connecter depuis un navigateur à l'adresse xxx.xxx.xxx.1
// par exemple : sur livebox : plage adresses DHCP entre .10 et .50 => on peut utiliser .100 pour le shield ethernet
// --- Déclaration des objets utiles pour les fonctionnalités utilisées ---
//--- création de l'objet serveur ----
EthernetServer serveurHTTP(80); // crée un objet serveur utilisant le port 80 = port HTTP
String chaineRecue=""; // déclare un string vide global pour réception chaine requete
int comptChar=0; // variable de comptage des caractères reçus


void setup() { // debut de la fonction setup()
// --- ici instructions à exécuter 1 seule fois au démarrage du programme ---
// ------- Initialisation fonctionnalités utilisées -------
pinMode(LED,OUTPUT); // broche en sortie
digitalWrite(LED,etatLED); // met la LED dans l'état voulu - éteinte au début
Serial.begin(9600); // Initialise connexion Série
//---- initialise la connexion Ethernet avec l'adresse MAC du module Ethernet, l'adresse IP Locale
//---- +/- l'adresse IP du serveurDNS , l'adresse IP de la passerelle internet et le masque du réseau local
//Ethernet.begin(mac); // forme pour attribution automatique DHCP - utilise plus de mémoire Flash (env + 6Ko)
Ethernet.begin(mac, ipLocal); // forme conseillée pour fixer IP fixe locale
//Ethernet.begin(mac, ipLocal, serverDNS, passerelle, masque); // forme complète
delay(1000); // donne le temps à la carte Ethernet de s'initialiser
Serial.print("Shield Ethernet OK : L'adresse IP du shield Ethernet est : " );
Serial.println(Ethernet.localIP());
//---- initialise le serveur ----
serveurHTTP.begin();
Serial.println("Serveur Ethernet OK : Ecoute sur port 80 (http)");
} // fin de la fonction setup()


void loop(){ // debut de la fonction loop()
// crée un objet client basé sur le client connecté au serveur
EthernetClient client = serveurHTTP.available();
if (client) { // si l'objet client n'est pas vide
// le test est VRAI si le client existe
// message d'accueil dans le Terminal Série
Serial.println ("--------------------------");
Serial.println ("Client present !");
Serial.println ("Voici la requete du client:");
////////////////// Réception de la chaine de la requete //////////////////////////
//-- initialisation des variables utilisées pour l'échange serveur/client
chaineRecue=""; // vide le String de reception
comptChar=0; // compteur de caractères en réception à 0
if (client.connected()) { // si le client est connecté
/////////////////// Réception de la chaine par le réseau ////////////////////////
while (client.available()) { // tant que des octets sont disponibles en lecture
// le test est vrai si il y a au moins 1 octet disponible
char c = client.read(); // l'octet suivant reçu du client est mis dans la variable c
comptChar=comptChar+1; // incrémente le compteur de caractère reçus
Serial.print(c); // affiche le caractère reçu dans le Terminal Série
//--- on ne mémorise que les n premiers caractères de la requete reçue
//--- afin de ne pas surcharger la RAM et car cela suffit pour l'analyse de la requete
if (comptChar<=100) chaineRecue=chaineRecue+c; // ajoute le caractère reçu au String pour les N premiers caractères
//else break; // une fois le nombre de caractères dépassés sort du while
} // --- fin while client.available = fin "tant que octet en lecture"
Serial.println ("Reception requete terminee");



/////////////////// Affichage de la requete reçue //////////////////////
Serial.println(F("------------ Affichage de la requete recue ------------")); // affiche le String de la requete
Serial.println (F("Chaine prise en compte pour analyse : "));
Serial.println(chaineRecue); // affiche le String de la requete pris en compte pour analyse
/////////////////// Analyse de la requete reçue //////////////////////
Serial.println(F("------------ Analyse de la requete recue ------------")); // analyse le String de la requete
//------ analyse si la chaine reçue est une requete GET --------
if (chaineRecue.startsWith("GET")) { // si la chaine recue commence par GET
Serial.println (F("Requete HTTP valide !"));
//----- extraction et analyse de la sous-chaine utile ------
String requeteUtile=chaineRecue.substring(0, chaineRecue.indexOf('\n')); // garde la sous-chaine jusqu'au premier saut de ligne
Serial.println("Requete recue par serveur = " + requeteUtile); // message texte qui va s'afficher dans le navigateur client
if (requeteUtile.indexOf("LED=ON")!=-1) { // si la chaine voulue est dans la réponse utile - indexOf() renvoie -1 si sous-chaine pas trouvée
Serial.println("La chaine LED=ON est valide");
etatLED=HIGH; // mémorise état LED
} // fin if LED=ON
else { // sinon = si pas LED=ON
Serial.println("Pas de chaine LED=ON ");
etatLED=LOW; // mémorise état LED
} // fin else
digitalWrite(LED,etatLED); // met la LED dans l'état voulu


/////////////// Réponse HTTP suivie de la Page HTML de réponse //////////////////
//-- envoi de la réponse HTTP ---
client.println("HTTP/1.1 200 OK"); // entete de la réponse : protocole HTTP 1.1 et exécution requete réussie
client.println("Content-Type: text/html"); // précise le type de contenu de la réponse qui suit
client.println("Connnection: close"); // précise que la connexion se ferme après la réponse
client.println(); // ligne blanche
//--- envoi en copie de la réponse http sur le port série
Serial.println("La reponse HTTP suivante est envoyee au client distant :");
Serial.println("HTTP/1.1 200 OK");
Serial.println("Content-Type: text/html");
Serial.println("Connnection: close");
Serial.println();
//--- la réponse HTML à afficher dans le navigateur
//----- ici on renvoie le code HTML du formulaire
// envoie les chaines de caractères voulues = du code HTML


//--- la réponse HTML à afficher dans le navigateur
//----- ici on renvoie le code HTML du formulaire
// envoie les chaines de caractères voulues = du code HTML
//------ début de la page HTML -------
client.println("<!DOCTYPE html>");
client.println("<html>");
//------- head = entete de la page HTML ----------
client.println("<head>");
client.println("<meta charset=\"utf-8\" />"); // fixe encodage caractères - utiliser idem dans navigateur
client.println("<title>Titre</title>");// titre de la page HTML
client.println("</head>");
//------- fin head = fin entete de la page HTML ----------
//------- body = corps de la page HTML ----------
client.println("<body>");
// affiche chaines caractères simples
client.println("<CENTER>"); //pour centrer la suite de la page
client.println("<br>");
client.println("formulaire HTML de controle d'une LED");
client.println("<br>");
client.println("SI-Lycée Germaine Tillion");
client.println("<br>");
// intègre une image - suppose connexion internet disponible
client.println("<CENTER> <img src=\"https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcR-Xihdzai7zTpJgtG_OKtJd1qhM_mRA185blKkU2WO-S-BinUy\"> </CENTER>");




//-------- debut du formulaire -------
client.print("<form method=get action=\"http://");
client.print(Ethernet.localIP()); // adresse IP du shield
client.println("\">");
// case à cocher tenant compte état LED "" ou "checked"
client.print("<INPUT type=\"checkbox\" value=\"ON\" name=\"LED\"");
if (etatLED==HIGH) client.print(" checked"); // si la LED est HIGH la case à cocher est "checked"
client.println("> Allumer la LED");
client.println("<br>"); // saut de ligne HTML
client.println("<INPUT type=\"submit\" value=\"Envoi\" name=\"Envoi\">"); // bouton d'envoi
client.println("</form>");
//-------- fin du formulaire -------
//---- infos sur l'état de la LED ----
client.println("<br>"); // saut de ligne HTML
if (etatLED==HIGH) client.println("La LED est ON");
else client.println("La LED est OFF");
client.println("</CENTER>"); //fin centrage de la page
client.println("</body>");
//------- fin body = fin corps de la page ----------
client.println("</html>");
//-------- fin de la page HTML -------
} // fin if GET



else { // si la chaine recue ne commence pas par GET
Serial.println (F("Requete HTTP non valide !"));
} // fin else
//------ fermeture de la connexion ------
// fermeture de la connexion avec le client après envoi réponse
delay(1); // laisse le temps au client de recevoir la réponse
client.stop();
Serial.println(F("------------ Fermeture de la connexion avec le client ------------")); // affiche le String de la requete
Serial.println (F(""));
} // --- fin if client connected
} //---- fin if client ----
} // fin de la fonction loop()
