Sion

Ne voyez dans ce titre pour le moins énigmatique aucune référence biblique, à une quelconque localité du Gers ou de Suisse. Juste un petit clin d’oeil à une certaine trilogie

Voici un projet classique, mais riche d’enseignements : avoir une vue de la température et de l’humidité des pièces de la maison et de l’extérieur via un navigateur web.

Vue de la température extérieure

I Le matériel

– Autant de couples Arduino Uno / Ethernet Shield que d’endroits à monitorer

– Des sondes de température DHT11 et DHT22 (la sonde DHT22 est plus chère, mais accepte les températures négatives : -40°c à +80°c : idéale pour l’extérieur).

– Autant de cartes micro-sd que de shields ethernet, la plus petite capacité suffit, on n’y mettra qu’un fichier  hlml.

– Un moyen de faire passer des communications ethernet : adaptateurs CPL, vieux routeur WIFI converti en client, câbles ethernet…

II On câble

Rien de bien compliqué, voici le schéma avec 2 sondes, hors ethernet shield :

 

Cablage des sondes

 

ps : chez moi, les résistances ont une valeur de 4,7 K

Pour plus d’explications sur le fonctionnement d’un capteur DHT11, allez voir ici :

http://skyduino.wordpress.com

III On code

Là, cela devient (un peu) plus complexe.

Tout d’abord, merci à ce site : http://startingelectronics.com/ sans lequel je n’y serai peut-être pas arrivé…

La théorie :

Le shield ethernet fait fonctionner de manière native un (petit) serveur web. Nous sommes loin d’un serveur lamp, mais cela suffit amplement pour notre application.

Le but est donc :

– l’Arduino mesure en continu les valeurs relevées par une ou plusieurs sondes DHT

– Si un client se connecte via un navigateur web, on lui renvoie une page html formatée contenant les valeurs des dites sondes.

Ce qui donne pour la partie Arduino :


 »

#include <DHT.h>
#include <Ethernet.h>
#include <SPI.h>
#include <SD.h>

#define DHT1PIN 2 // pin de la sonde dht11
#define DHT1TYPE DHT11 // type de sonde (THT11, DHT22…)

DHT dht1(DHT1PIN, DHT1TYPE); // on declare la sonde

// Taille du buffer pour les requetes http
#define REQ_BUF_SZ 50

// pour le serveur web :
byte mac[] = {0x90,0xA2,0xDA,0x0F,0x39,0x70}; // Adresse mac de l’ethernet shield
byte ip[] = {192,168,250,232}; // Adresse ip de la carte
float tempLue; //Valeur de l’entrée
EthernetServer server(80); // Assignation du port d’écoute (http)

String readString;
File webFile; // Fichier sur carte SD
char HTTP_req[REQ_BUF_SZ] = {0};
char req_index = 0;

// variables pour calcul de la temperature et humidite

float temperatureInt;
float humiditeInt;

// on intialise…
void setup() {

// pin à passer High pour le chip ethernet
pinMode(10, OUTPUT);
digitalWrite(10, HIGH);

Serial.begin(9600); // Pour debug

// init de la carte SD
Serial.println(« Init de la carte SD… »);
if (!SD.begin(4)) {
Serial.println(« Erreur : init impossible… »);
return; // init impossible
}
Serial.println(« Carte SD OK »);
// cherche le fichier « index.html »
if (!SD.exists(« index.htm »)) {
Serial.println(« Erreur : pas de fichier index.html »);
return; // fichier index.html introuvable
}
Serial.println(« OK Fichier index.html trouve »);

Ethernet.begin(mac, ip); // init du périphérique ethernet
server.begin(); // init du serveur web

dht1.begin(); // init de la sonde DHT11
}
// fin du setup
void loop()
{
EthernetClient client = server.available(); // on cherche un client

if (client) { // client trouve ?
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) { // si le client envoie une chaine lisible
char c = client.read(); //lecture de 1 byte (character) depuis le client
// mise en tampon de la premiere partie de la requette HTTP : HTTP_req array (string)
// jusqu’a ce que le dernier element du tableau soit un caractere null (REQ_BUF_SZ – 1)
if (req_index < (REQ_BUF_SZ – 1)) {
HTTP_req[req_index] = c; // sauve la requette HTTP
req_index++;
}
// la derniere ligne du client est une ligne « blanche » et se termine par \n
// on repond au client seulement apres reception de la derniere ligne
if (c == ‘\n’ && currentLineIsBlank) {
// envoi d’un standard http response header (en tete HTTP)
client.println(« HTTP/1.1 200 OK »);

// Ajax requette – envoi d’un fichier XML
if (StrContains(HTTP_req, « ajax_inputs »)) {
// envoi du reste du HTTP header
client.println(« Content-Type: text/xml »);
client.println(« Connection: keep-alive »);
client.println();
// envoi du fichier XML contenant l’etat des entrees
XML_response(client);
}
else { // web page requette
// envoi du reste de l’HTTP header
client.println(« Content-Type: text/html »);
client.println(« Connection: keep-alive »);
client.println();
// envoi de la page web
webFile = SD.open(« index.htm »); // ouverture du fichier contenant la page web
if (webFile) {
while(webFile.available()) {
client.write(webFile.read()); // envoi de la parge web au client
}
webFile.close();
}
}
// affichage sur le port serie des requettes HTTP
Serial.print(HTTP_req);
// remise des tampons a 0
req_index = 0;
StrClear(HTTP_req, REQ_BUF_SZ);
break;
}
// chaque ligne de texte recue du client se termine par \r\n
if (c == ‘\n’) {
// si on est au dernier caractere de la ligne recue,
// on demarre une nouvelle ligne avec le nouveau caractere lu
currentLineIsBlank = true;
}
else if (c != ‘\r’) {
// un caractere texte est recu du client
currentLineIsBlank = false;
}
} // fin du if (client.available())
} // fin du while (client.connected())
delay(1000); // laisse le temps au navigateur web pour recevoir les données (nota : 1 par defaut, trop court chez moi)
client.stop(); // ferme la connexion
} // fin du if (client)
}

// envoi du fichier XML contenant les valeurs des entrées
void XML_response(EthernetClient cl)
{

humiditeInt = dht1.readHumidity(); // lecture de la sonde pour l’humidite

temperatureInt = dht1.readTemperature(); // lecture de la sonde pour la temperature
// les inputs pour ajax
cl.print(« <?xml version = \ »1.0\ » ?> »);
cl.print(« <inputs> »);
cl.print(« <tempint> »);
cl.print((float)temperatureInt, 2);
cl.print(« </tempint> »);
cl.print(« <humint> »);
cl.print((float)humiditeInt, 2);
cl.print(« </humint> »);
cl.print(« </inputs> »);

}

// on efface les tableaux
void StrClear(char *str, char length)
{
for (int i = 0; i < length; i++) {
str[i] = 0;
}
}

// cherche la chaine sfind dans la chaine str
// renvoie 1 si trouve
// renvoie 0 si pas trouve
char StrContains(char *str, char *sfind)
{
char found = 0;
char index = 0;
char len;

len = strlen(str);

if (strlen(sfind) > len) {
return 0;
}
while (index < len) {
if (str[index] == sfind[found]) {
found++;
if (strlen(sfind) == found) {
return 1;
}
}
else {
found = 0;
}
index++;
}

return 0;
}

 »


 

J’ai essayé de commenter au maximun, sachant que la partie communication réseau est une adaptation de celle utilisée par http://startingelectronics.com/projects/arduino-projects/.

Dans le principe, le code consiste à :

– importer les librairies nécessaires

– définir une adresse IP et une adresse mac pour le shield ethernet (serveur web)

– passer au serveur web un fichier « index.html » stocké à la racine de la carte SD

– attendre une connexion sur le dit serveur web

– si connexion, envoi d’un fichier XML contenant les valeurs des sondes DHT.

Nota : à la ligne 126, il y a un délai afin de laisser le temps au client web de recevoir les données. J’ai dû le mettre à 1000 ms chez moi. Peut-être parce-que j’utilise un mix CPL / WIFI / relais WIFI, ce qui n’améliore pas la vitesse du réseau…

… Et la partie HTML (fichier index.html), ici la version mono sonde :


 

<!DOCTYPE html>
<html>
<head>
<title>Climat Bureau Vincent</title>

<style>
.txt_block {
width: 250px;
height: 250px;
padding-left: 10px;
float: left;
position: relative; /* on positionne le conteneur */
margin-left: auto;
margin-right: auto;
text-align: center;
style= »color:#c2c2c2″;
}

h1 {
font-family: courier, courier-new, serif;
font-size: 20pt;
color: blue;
font-style: italic;

}

h2 {
font-family: courier, courier-new, serif;
font-size: 15pt;
color: red;

}

.Degrade {
background-image:linear-gradient(white, grey);
}
</style>

<script>
function GetArduinoInputs()
{
nocache = « &nocache= » + Math.random() * 1000000;
var request = new XMLHttpRequest();
request.onreadystatechange = function()
{
if (this.readyState == 4) {
if (this.status == 200) {
if (this.responseXML != null) {
// extract XML data from XML file (containing switch states and analog value)

document.getElementById(« input2 »).innerHTML =
this.responseXML.getElementsByTagName(‘tempint’)[0].childNodes[0].nodeValue;
document.getElementById(« input3 »).innerHTML =
this.responseXML.getElementsByTagName(‘humint’)[0].childNodes[0].nodeValue;
}
}
}
}
request.open(« GET », « ajax_inputs » + nocache, true);
request.send(null);
setTimeout(‘GetArduinoInputs()’, 1000);
}
</script>
</head>

<body onload= »GetArduinoInputs() »>

<body bgcolor= »b1d0b8″>

<div class= »txt_block »>
<h1>Temperature :</h1>
</br>
<p><h2><span id= »input2″>… deg</span></h2></p>

</div>

<div class= »txt_block »>
<h1>Humidite :</h1>
</br>
<p><h2><span id= »input3″>… %</span></h2></p>

</div>

</body>
</html>


 

ce qui donne :

ClimaBureauVince

 

Conclusions / améliorations

Je n’ai pas parlé de la partie mise en réseau, car elle dépend des besoins de chacun. Personnellement, ayant de part mon travail un certain stock de « vieux » routeurs Lynksys WRT54gl sous DDWRT, je les ai recyclé en client WIFI, auxquels j’ai branché les Arduino avec un câble ethernet. Si vous voulez plus de détails, mailez moi…

Sinon, le système fonctionne depuis maintenant 8 mois, on y accède via une page html contenant des images à cliquer qui pointent sur chaque sonde (affichage d’un pop-up). Cela devient très rapidement addictif…

Comme toujours, pour tout commentaire, info, critique (constructive…), c’est ici :

 

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion /  Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion /  Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion /  Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion /  Changer )

Connexion à %s