dimanche 5 mai 2013 (), par
A la demande de absolut_man sur jeuxvideopc.com, qui était intéressé par ma proposition d’aide pour réaliser un site web,
Le projet de bac spé ISN consiste en un robot qui mesure la température et qui la communique sur un site internet. Pas d’une grande utilité à priori mais cela permet de balayer tout le programme de l’année.
Deux cartes arduinos sont utilisées pour la mesure météorologique :
Le problème était : comment faire pour mettre à jour automatiquement les données sur le site internet ?
en fait c’est assez facile
il faut sur le serveur :
sur le pc, il suffit d’utiliser la librairie python permettant de faire des requêtes HTTP.
voir là.
la requête sera donc du type http://le_site/page_php.php?paramètre1=valeur1¶mètre2=valeur2
.
la page php permettra de mettre à jour la base de données.
python ne créé pas de liste, il envoie les données 1 par 1 à un script php, qui insère les données dans une base.
un script php affichera ensuite une donnée unique ou une liste, selon ce qui est prévu. donnée unique mise à jour par l’AJAX, liste éventuellement sous forme graphique pour présenter l’évolution.
la base n’a besoin que d’une seule table : releves, contenant 3 champs
tous ces champs sont non nuls, non uniques.
l’index PRIMARY KEY
(clé primaire, permettant d’identifier de manière unique une ligne de la table) sera la combinaison du numéro de sonde et de la date/heure du relevé de température.
Ce script est extrêmement simple : Il reçoit en entrée plusieurs variables et les insère dans la base.
<?php
if (isset($_GET["sonde"])){
$sonde=$_GET["sonde"];
}else{
$sonde=1; // par défaut
}
if (isset($_GET["temper"])){
$temper=$_GET["temper"];
}
le script PHP étant appelé par un script python, l’envoi des données se fait dans l’url de la requête html générée par le script python.
la méthode est donc GET
.
la récupération des variables se fait alors par $_GET["variable"]
par sécurité autant que par simplicité, on vérifie l’existence de la variable (dans la requête) avant d’essayer de récupérer sa valeur, avec la fonction isset(variable)
.
Et pour simplifier encore plus, on rend certaines variables optionnelles en prévoyant des valeurs par défaut.
Ainsi, s’il n’y a qu’une seule sonde et/ou qu’on ne souhaite pas se compliquer en envoyant la date/heure sous un format complexe, le script php s’en charge.
if (isset($_GET["quand"])){
$quand=$_GET["quand"];
}else{
$quand=date("Y-m-d H:i:s"); // par défaut, date actuelle
// format YYYY-MM-DD HH:MM:SS ===> datetime en MYSQL
}
la date/heure, justement, doit être au format datetime
de MySQL pour être insérée en base, à savoir de type YYYY-MM-DD HH:MM:SS
// connexion à la base SQL et insertion des données
include_once "connect.php";
Pour se connecter à la base, on fait appel à un autre script, ce qui permet d’avoir plusieurs scripts PHP différents utilisant la même méthode de connexion, rendant les changements et corrections plus faciles.
<?php
mysql_connect('
adresse serveur MySQL','
utilisateur MySQL','
mot de passe','MYSQL');
mysql_select_db("
nom de la base");
?>
Puis, si la température est définie et que la variable contient une valeur, on insère les données.
if (isset($temper)&&$temper!=null){
$reki="insert into releves (sonde,date,temperature) values ($sonde,'$quand',$temper)";
$resi=mysql_query($reki);
}
?>
null
est un mot clé signifiant "rien". Pas zéro, pas chaîne vide, mais rien, pas de valeur. la variable existe mais n’est pas initialisée. C’est un peu comme s’il y avait un feu tricolore, mais éteint. Il est là, il existe, mais il n’est pas vert, orange ou rouge et n’a donc pas de "valeur".
la requête SQL est très simple, l’ordre étant insert
dans la table releves dans les champs correspondants sonde, date, temperature
des valeurs $sonde, $quand, $temper
.
Par sécurité, on aurait pu ajouter un système de clé ou autre moyen d’authentifier le "client" envoyant la requête de mise à jour, que ce soit au niveau du script php, au niveau du serveur web Apache (SSL), ou même ou niveau du pare-feu iptables (chaîne mangle) sous Linux.
Le problème ne se posant pas sur ce projet et par souci de simplicité, cela n’a pas été envisagé.
La page html est assez simple
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="fr" dir="ltr" xml:lang="fr" xmlns="http://www.w3.org/1999/xhtml">
On indique :
xhtml1 transitionnal
. Les types de documents normalisés W3C définissent le contenu utilisable et permettent un traitement homogène par les navigateurs respectant ces normes.dir = ltr
, left-to-right, de gauche à droite <head>
<title>Projet Celcius (ISN)</title>
<meta http-equiv="content-Type" content="text/html; charset=UTF-8"/>
<meta name="description" content="Projet Celcius"/>
<link media="all" type="text/css" href="style.css" rel="stylesheet"/>
<script type="text/javascript" src="absolut.js"> </script>
</head>
en entête de page, on fournit d’autres informations comme le titre de la page, l’encodage des caractères, la description rapide du contenu.
Une feuille de style CSS et un fichier de script JavaScript sont également appelés.
<body onload="AuChargement();">
<div id="head">
<h1>Projet Celcius - Mesure de la température</h1>
</div>
La page se divise en 2 blocs : entête et contenu.
le bloc contenu contiendra un petit texte explicatif ainsi que le bloc "température", dont le contenu sera mis à jour et dédié à l’affichage de la température.
<div id="content">
<h2>¤ Bienvenue sur le site de notre Projet ISN ¤</h2>
<p><b>Intitulé du projet :</b> Réaliser un programme et mettre en oeuvre des équipements permettant à un robot Mindstorm NXT de se déplacer dans une pièce en évitant les obstacles et de transmettre des
mesures de température rafraîchies automatiquement sur un site internet.</p>
<h3>Température en temps réel :</h3>
Le bloc "température" contient par défaut une valeur quelconque, qui sera ensuite mise à jour par le script JavaScript qui demandera à un script PHP une valeur en base de données, avant d’insérer ladite valeur dans la page.
<div id="temperature"><i>en attente de mise à jour</i></div>
Au cas où l’utilisateur aurait désactivé JavaScript, un bloc sera par défaut affiché. Si Javascript est activé, une fonction cachera ce bloc.
<div id="jsornotjs">
Vous avez désactivé JavaScript. JavaScript est requis pour le rafraîchissement des données de température relevées par le robot sur le site.
</div>
Puis on ferme le bloc contenu, le corps de page et la page.
</div>
</body>
</html>
Ce qui donne ceci :
AJAX consiste à envoyer de manière asynchrone une requête de type XMLHttpRequest
et d’effectuer ensuite un traitement du document XML fourni en réponse.
Il faut donc d’abord une fonction pour créer l’objet XMLHttpRequest
function get_requete_maj_temp(){
var requete_maj_temp=null;
Ici, la variable requete_maj_temp
est initialisé à vide. Si la fonction s’exécute correctement, elle contiendra un objet de type XMLHttpRequest
Selon le navigateur, la fonction à utiliser est différente :
window.XMLHttpRequest
sous Firefoxnew ActiveXObject("Msxml12.XMLHTTP")
ou new ActiveXObject("Microsoft.XMLHTTP")
sous IE, selon la version. if (window.XMLHttpRequest){ // Firefox
requete_maj_temp=new XMLHttpRequest();
}else if (window.ActiveXObject){ // IE
des blocs try { } catch (
erreur) { }
permettent "d’essayer" de réaliser certaines actions, et de récupérer le code/message d’erreur dans la variable erreur avant d’exécuter d’autres actions en cas d’échec de l’essai.
Cela permet dans cette fonction de tester les différentes versions d’Internet Explorer.
try{
requete_maj_temp=new ActiveXObject("Msxml12.XMLHTTP");
}catch(e){
try{
requete_maj_temp=new ActiveXObject("Microsoft.XMLHTTP");
}catch(e1){
requete_maj_temp=null;
}
}
}else{ // non supporte
alert("Votre navigateur ne supporte pas les XMLHTTPRequest.");
}
Une fois fini, que l’objet soit créé ou non, on retourne la variable.
Celle-ci contient null
si on n’a pas pu créer d’objet XMLHttpRequest
return requete_maj_temp;
}
Ensuite, cet objet doit être envoyé à un script sur un serveur
On fournit à cette fonction l’adresse où envoyer la requête.
function requete_requete_maj_temp(url){
On tente de créer la requête en utilisant la fonction déclarée précédemment.
requete_maj_temp=get_requete_maj_temp();
Si la variable n’existe pas ou si elle contient null
, on affiche un message d’erreur et on quitte la fonction par la directive return
.
if ((!requete_maj_temp)&&(requete_maj_temp!=null)){
alert("Votre navigateur ne peut creer de requete AJAX.");
return;
}
Sinon, on définit la fonction JavaScript chargée de traiter la réponse et on envoie la requête.
requete_maj_temp.onreadystatechange=function(){traitementReponse_requete_maj_temp(requete_maj_temp)}
requete_maj_temp.open("GET",url,true);
requete_maj_temp.send(null);
}
function traitementReponse_requete_maj_temp(requete_maj_temp){
var contenu;
la variable <contenu contiendra le document réponse XML.
Lorsque la requête sera dans l’état "4", à savoir présence d’une réponse, le traitement sera effectué.
if (requete_maj_temp.readyState==4){
On charge le contenu du document XML de réponse dans la variable
contenu=requete_maj_temp.responseXML;
Puis on récupère une par une les valeurs des différentes balises XML (tag) avec getElementsByTagName(
code_balise)
, qui renvoie un tableau de tous les éléments ayant ce tag Html/XML.
On cherche généralement le premier élément du tableau,
dont on récupère la valeur.
<code>
temper=contenu.getElementsByTagName("temperature")[0].firstChild.nodeValue;
dater=contenu.getElementsByTagName("date")[0].firstChild.nodeValue;
heurer=contenu.getElementsByTagName("heure")[0].firstChild.nodeValue;
sonde=contenu.getElementsByTagName("sonde")[0].firstChild.nodeValue;
Ensuite, si le bloc dédié à l’affichage des données existe dans la page Html affichée, on le met dans une variable afin de pouvoir y écrire les données reçues avec la directive variable_bloc.innerHTML=chaîne texte
.
if (this.document.getElementById('temperature')!=null){
var div_temp=this.document.getElementById('temperature'); // le div
div_temp.innerHTML="sonde "+sonde+" : "+temper+"°C le "+dater+" à "+heurer;
Enfin, pour continuer de mettre à jour les données affichées, on définit un compte à rebours, ici de 10 secondes (10 000 milli-secondes) avec la directive SetTimeout
pour appeler la fonction lançant la mise à jour et définie juste après.
setTimeout("maj_temp()",10000);
}
}
}
il aurait été possible de faire appel direct à function requete_requete_maj_temp(url) mais cette fonction encapsule l’url pour faire un appel plus simple
on pourrait aussi accepter des paramètres de maj_temp.php, comme le numéro de sonde
function maj_temp(){
if (this.document.getElementById('temperature')!=null){
requete_requete_maj_temp('maj_temp.php');
}
}
La fonction de mise à jour est lancée au chargement de la page (évènement onLoad
de l’élément body
), via cette fonction AuChargement, qui permet de lancer plusieurs traitements.
Cette fois, le compte à rebours est de 1 seconde, pour initialiser dans la page une valeur de la base de données.
// fonction pour les scripts a lancer au chargement de la page => body onLoad
function AuChargement(){
pisteIE();
cacherjs();
setTimeout("maj_temp()",1000); // 1 seconde
}
Ce script, appelé par la fonction JavaScript, est extrêmement simple.
Il récupère en base la dernière valeur de température pour une sonde donnée, la sonde "par défaut" étant la 1.
<?php
// recuperation des champs
if (isset($_GET["sonde"])){
$id=$_GET["sonde"];
}else{
$id=1; /* sonde par defaut */
}
On génère ensuite l’entête du document réponse...
header('content-Type:text/xml,charset=UTF-8');
...avant de se connecter à la base, récupérer les valeurs...
include_once "connect.php";
$rek="select sonde,DATE_FORMAT(date,'%d/%m/%Y') as date, DATE_FORMAT(date,'%H:%i:%s') as heure,temperature from releves where sonde=$id order by date DESC limit 0,1";
$res=mysql_query($rek);
$row=mysql_fetch_array($res,MYSQL_ASSOC);
$sonde=$row["sonde"];
$date=$row["date"]; // a transformer en texte
$heure=$row["heure"]; // de meme
$temperature=$row["temperature"];
... et de les mettre dans le document XML.
new DOMDocument("1.0","utf-8");
createElement('root');
suivi de appendChild();
createElement(nom_balise, valeur);
suivi de appendChild();
$doc=new DOMDocument("1.0","utf-8");
$racine=$doc->createElement('root');
$doc->appendChild($racine);
$xmlsonde=$doc->createElement('sonde',$sonde);
$racine->appendChild($xmlsonde);
$xmldate=$doc->createElement('date',$date);
$racine->appendChild($xmldate);
$xmlheure=$doc->createElement('heure',$heure);
$racine->appendChild($xmlheure);
$xmltemp=$doc->createElement('temperature',$temperature);
$racine->appendChild($xmltemp);
et enfin envoyer le document.
echo $doc->saveXML();
?>