Techniques "avancées" de serveur web sur ESP8266

3. Aller plus loin: AJAX et XML

imaginons maintenant que vous ayez un certain nombre de valeurs (des éléments mesurés de votre programme arduino par exemple comme la température, l'humidité, l'état d'un potentiomètre etc...) que vous voulez afficher de temps en temps

On pourrait prendre la même approche que ci dessus et générer un gros bout de code HTML pour la mise en page du résultat mais on retombe alors dans les problèmes de vitesse d'affichage, plus la réponse à la requête HTTP est grande et moins on aura l'impression que l'interface web est réactive. de plus ça oblige à coder en dur du HTML dans le programme Arduino et donc on n'est plus libre de choisir la mise en page HTML / CSS que l'on souhaite. si on veut changer la page web, on doit changer et re-compiler le code Arduino...

Si on se souvient que JavaScript est un langage de programmation ayant accès comme on l'a vu à l'arborescence objet représentant la page web (DOM) on pourrait se dire que si le code HTML pouvait simplement dire "ici afficher la valeur de la variable x" et si on pouvait depuis une réponse dire simplement dire "x vaut maintenant 18" alors on obtiendrait cette indépendance entre le code Arduino et le code HTML.

c'est exactement ce que l'on va faire :slight_smile:

Un peu d'info sur XML (eXtensible Markup Language)

il y a beaucoup d'info sur XML en ligne, par exemple XML expliqué aux débutants et vous pouvez aussi lire le document officiel de La spécification XML du 26 November 2008 (c'est pas récent comme vous pouvez le constater)

On retiendra surtout que

  • XML est un langage de balisage utilisant les symboles <> par exemple

  • Il doit toujours y avoir une balise ouvrante et une balise fermante <toto>...</toto>

  • Si on n'a rien entre deux balises, il existe une forme restreinte avec un / en fin de balise <toto/>

  • On peut affecter des attributs délimités obligatoirement par des guillemets ou des apostrophe aux éléments (valeurs des entités) par exemple <toto age="12" comportement="blagueur"/>

  • les balises sont organisées en arbre (aucun chevauchement n'est autorisé) il y a donc une balise qui englobe toutes les autres et qui est la racine de l'arbre

<racine>
   <enfants>
      <fred age="12" comportement="blagueur"/>
      <paul age="14" comportement="douteux"/>
   </enfants>
</racine>
  • un "prologue" XML sert à définir la version de XML qu'on utilise ou l'encodage (attribut encoding -> par défaut UTF-8) par exemple et se représente ainsi. (vous utilisez quasiment toujours la version 1.0
<?xml version="1.0" ?>

comme la plupart des éditeurs de texte sauvent le fichier par défaut en ISO-8859-1, vous verrez le plus souvent plutôt

<?xml version="1.0" encoding="ISO-8859-1"?>

Comment l'utiliser ?

On pourrait envisager un fichier XML (sauvé en UTF-8) structuré ainsi:

<?xml version = "1.0" ?>
<variables>
   <bouton>actif</bouton>
   <digital1>1</digital1>
   <analog1>432</analog1>
</variables>

ou alors comme cela

<?xml version = "1.0" ?>
<variables>
   <bouton>actif</bouton>
   <bouton>1</bouton>
   <analog>432</analog>
</variables>

On dit qu'on a un arborescence qui s'appelle variables et qui contient 3 éléments. La différence entre les 2 (on verra que c'est utile plus tard) c'est que dans le premier cas chaque élément a un nom unique alors que dans le second cas on dit qu'on a deux types d'éléments, deux boutons (car même nom) et une valeur analogique


Bon c'est bien toute cette théorie mais comment en Javascript vais-je aller extraire des valeurs et les affecter dans la page?

un peu comme avant...

Si au lieu de retourner donc du code HTML qui servirait comme précédemment à remplacer un noeud de l'arborescence DOM on retourne du XML, on peut écrire un script JavaScript qui va aller comprendre le contenu du XML pour trouver quels noeuds DOM modifier et injecter la bonne valeur.

Si vous regardez un peu plus haut quand on retournait du contenu HTML, dans le header HTTP on disait

HTTP/1.1 200 OK
Content-Type: text/html
Connection: keep-alive

mais maintenant comme on va retourner du XML, dans le header de la réponse il faudra préciser que c'est du XML pour que notre script sache quoi en faire et donc on mettra avant le XML l'en-tête suivant:

HTTP/1.1 200 OK
Content-Type: text/xml
Connection: keep-alive

Commençons par travailler avec la première forme XML pour le moment.

<?xml version = "1.0" ?>
<variables>
   <bouton>actif</bouton>
   <digital1>1</digital1>
   <analog1>432</analog1>
</variables>

c'est ce que doit nous retourner l'Arduino pour répondre à une requête AJAX. On se souvient que la réponse du serveur web traitée par le Javascript était dans this.responseText.

Ici comme on va renvoyer du XML on ira regarder la réponse dans [b]this.responseXML[/b] qui représente notre arbre XML reçu en réponse; JavaScript comprend tout seul la structure d'un objet XML et donc on peut par programme demander à extraire des éléments de l'arbre par leur nom. Par exemple pour trouver le bout de XML correspondant à analog1 on va faire

this.responseXML.getElementsByTagName('analog1')

il se pourrait (comme on l'a vu ci dessus) que notre XML contienne plusieurs éléments portant un même nom. donc le getElementsByTagName() retourne en fait un tableau de tous ces éléments. ici on veut le premier, donc à l'index 0 du tableau et on écrira donc

this.responseXML.getElementsByTagName('analog1')[ 0 ]

Cet élément peut avoir plusieurs sous branches (enfants, child en anglais) et on s'intéresse (vu notre XML ci dessus) uniquement à la première entrée. Pour cela on peut soit utiliser childNodes[ 0 ] soit firstChild qui est le premier enfant de la liste.

Enfin on veut extraire la valeur 432 et c'est la valeur de notre noeud, que l'on trouver avec [b].nodeValue[/b]. Donc au final, pour aller extraire la valeur stockée dans notre XML pur le nom analog1 on va demander donc pour lire le 432

this.responseXML.getElementsByTagName('analog1')[0].childNodes[ 0 ].nodeValue

Ensuite on va utiliser la même technique que précédemment: on va remplacer dans l'arbre DOM le HTML associé à un noeud de nom particulier par cette nouvelle valeur et donc on va écrire:

document.getElementById("analog1ID").innerHTML = this.responseXML.getElementsByTagName('analog1')[ 0 ].childNodes[0].nodeValue;

il nous faudra bien sûr avoir défini dans le corps du HTML une zone portant le nom [color=blue]analog1ID[/color], par exemple en utilisant <span>

la pin A0 vaut <span id="analog1ID"]>...</span>