Mon Arduino en Wifi avec une Fonera et données mises à jour sur Pachube !

Gros changements pour mon Arduino !

D’abord, il hérite d’un shield Ethernet, ce qui va me permettre de le faire communiquer directement avec le web et/ou de présenter les données sur un serveur http interne. J’ai acheté le Shield Ethernet Standard pour m’assurer de la compatibilité, surtout par rapport aux PINs du Mega. Comme le Shield Ethernet a une carte micro-SD intégrée, je peux désormais enlever le module SD de Futurlec que j’avais acheté en plus. La librairie est la même, mais cela me libère des ports d’input/output car la communication se fait sur le bus SPI de l’Arduino.

Bon, ça c’est déjà bien. Mais voilà, moi je souhaiterais que mon Arduino puisse communiquer librement… donc il me faut du wi-fi. Mmmh qu’est-ce que je pourrais bien utiliser comme routeur ou repeteur de mon signal wifi, histoire d’y connecter mon Arduino et son beau shield ethernet ? Tiens donc, c’est pas une Fonera qui traine par là-bas ? Si vous ne savez pas ce qu’est une Fonera, c’est un routeur bon marché lancé par Fon qui a l’énorme avantage de pouvoir être hacké, surtout les premières versions. Ô chance, ma Fonera est justement le tout premier modèle. Il "suffit" d’y installer OpenWRT ou DD-WRT (option que j’ai choisie). Je dis "suffit" entre guillemets car le processus de hacking de la Fonera est assez délicat; cela m’a pris près d’une journée et j’ai dû m’y reprendre à plusieurs reprises !

Mais une fois DD-WRT installé, la Fonera peut agir en repeteur de réseau wifi, bridge etc etc. Et voilà donc mon Arduino connecté en wifi sur mon réseau, et prêt à affronter le monde !

Je ne résiste pas à l’envie de vous montrer ça, surtout pour prouver que la Fonera communique sur le réseau wifi.

//

Le monde justement… connecter l’Arduino c’est bien, oui mais à quoi ?

C’est là qu’entrent en jeu à la fois la librairie Twitter de l’Arduino et Pachube, un site qui collecte les streams de données récupérées par différents capteurs.

Le système a deux avantages. Non seulement les données sont disponibles sur le web — j’aurais pu les mettre sur mon serveur aussi — mais l’avantage ici c’est qu’il est possible de créer des alarmes et des graphes en ligne en temps réel. J’ai choisi de ne pas faire communiquer l’Arduino directement avec Pachube, et de passer par Twitter comme intermédiaire, car cela me permet d’avoir l’Arduino qui m’envoie des messages directs en cas d’alarme. Mieux que le SMS et gratuit ! Par chance, Pachube offre aussi une application pour cela, qui permet de mettre à jour les données par le biais de Twitter : PachTweet.

Et voilà le résultat de ces tests. Pour le moment, l’Arduino envoie toutes les 10 minutes la température actuelle à Pachube (cela risque de changer). Et cela sans aucune connection PC, uniquement l’envoi des données par le biais de la Fonera.

Voir le feed sur la page Pachube. (les valeurs sont encore approximatives, cela reste un test !)

Pas mal pour les derniers jours non ?

Design de la nouvelle rampe et status du contrôleur

Une petite mise à jour, d’abord pour le contrôleur, qui s’est vu adjoindre un capteur  de niveau (en test pour le moment) et une carte relais (en tests aussi). L’idée étant de contrôler l’éclairage (et autres pompes) par ce biais. Pour le moment, c’est encore de l’expérimentation.

Aujourd’hui j’ai un peu joué avec Google Sketchup pour dessiner ma nouvelle galerie d’aqua, qui devrait donc remplacer à terme le bricolage pas très heureux qu’il y a à l’heure actuelle. Cela laissera plein de place pour des montages de LED maison ET pour une partie contrôleur intégrée à la galerie.

Voici les plans du jour.

Rampe d'aquarium pour Trigon 350

Code du contrôleur sur Google Code

Vu que le code de mon contrôleur pour l’Arduino ne cesse de grandir, j’ai décidé de le mettre sur Google Code.

A prendre tel quel, c’est bien entendu du Work in Progress.

Du coup, j’ai aussi décidé de lui donner un nom, cela sera donc pour le moment "Yellow Tang Controller", du nom de ce superbe poisson (chirurgien jaune ou connu sous le nom de Zebrasoma Flavescens pour les amateurs !)

Contrôleur 2011 – on s’y remet !

Ouh là, cela fait depuis 2009 que je n’ai pas touché l’Arduino et mon modèle de controlleur d’aquarium (qui n’a pas avancé d’un iota depuis cette date).

Il est temps de s’y remettre…

Force est de constater que tout a changé !

J’utilisais la version 16/17 du logiciel Arduino, on en est à la 22. Les librairies ont changé (et évolué), ce qui fait que mon code ne fonctionne plus (ou quasi plus).

Par contre, il y a de nettes améliorations au niveau de la "RTC" (Real Time Clock) et des écrans LCD.

Vu que je dois reprendre le projet à la base, je décide de tout réviser. Et pour commencer, je change l’écran LCD pour un écran graphique que j’avais acheté il y a deux ans chez Futurlec, le CM12864-2. Il utilise une autre librairie que celle des écrans LCD standard, et tant mieux, car elle a bien évolué aussi (basé sur le driver KS0108). Cela me permettra d’être plus créative et par exemple, d’afficher des courbes de température, enfin dans l’idéal, parce que je n’ai pas encore testé !

Il y a également maintenant une libraire officielle pour la gestion des horloges, la librairie "Time", et il faut bien entendu que j’adapte mon code. Donc on recommence tout à zéro !

La première étape, c’est de câbler le nouvel écran, et par la même occasion, le capteur de température et l’horloge en temps réel.

Pour le moment, je n’ai testé les composants que séparément (en utilisant essentiellement les fichiers d’exemples fournis avec les librairies), pour m’assurer que le câblage est correct et que les données reçues sont adéquates.

L’étape suivante sera de revoir le code original et d’y apporter les modification nécessaires à l’utilisation du nouvel écran et des nouvelles librairies. On repart donc sur notre bonne vieille "planche d’essai" (breadboard en anglais, j’avoue ignorer le nom en français).

Une petite vidéo du test d’écran. Je précise que je n’ai absolument aucun mérite (à part celui d’avoir câblé correctement l’écran), le logiciel est l’un des exemples fournis dans la librairie de l’écran.

Gros bricolage du jour.. une boîte en carton !

Bon j’avoue c’est pas impressionnant. J’ai construit mon “micro-contrôleur” dans une boîte en carton (JMS reconnaitra la boîte de son digi-doseur ;) ), mais ça m’aide à voir quelles prises et connections seront utiles dans le futur, et la disposition des éléments. Que voulez-vous, je suis quelqu’un de “visuel”.

 

DSCF1339

A gauche, la sortie de la sonde température (un trou pour le moment, mais faudra une prise là ;) ). Le potentiomètre à côté de l’écran sert à régler la luminosité de celui-ci. J’ai tenté de faire une vidéo mais on ne voit rien sur l’écran LCD donc sans intérêt ;)

Ah sinon l’Arduino est encore à l’heure d’été donc en effet il est bien 19:36 au moment où j’ai pris la photo.

Un peu silencieuse… mais pas sans projets

Cela fait quelques semaines que je n’ai pas mis à jour ce blog, ce qui ne signifie pas que mes projets sont au point mort, bien au contraire !

L’urgence du moment, c’est que j’ai des spots halogènes dans ma cuisine dont les ampoules ne cessent d’exploser (probablement dû à une mauvaise installation initiale du cuisiniste) et que je commence à en avoir assez. Je suis en train de considérer un prototype de spot de remplacement en LEDs, en réalité une plaque de plexiglas qui sera composée soit de 80 LEDs, soit d’une 40aine en fonction du type de LED que je vais prendre (c’est à l’étude en ce moment).

En résumé, cela sera également un prototype pour l’éclairage de mes aquariums, d’abord pour mon aqua d’eau douce, ensuite peut-être pour le récifal. Tout cela probablement contrôlé, bien entendu.. par un Arduino, vous vous en doutez !

Dans la cuisine, l’idée est d’utiliser à la fois la détection de mouvement, un détecteur de lumière et une temporisation pour que l’éclairage s’allume automatiquement (et s’éteigne de même.)

Plus de détails lorsque la réalisation commencera !

Petite Evolution

Petits changements, peu spectaculaires (mais nécessaires !) pour mon contrôleur… soudé la plupart des câbles du LCD et de l’horloge sur une platine indépendante pour libérer de la place sur la platine d’essai (les températures négatives sont dues au fait qu’il n’y avait pas de capteur de branché à ce moment-là) DSCF1263

et remplacé le capteur de température par un LM35DZ, un processeur linéaire. Sa précision est moindre que celle du thermistor initial (il fonctionne par défaut par pas de 0.5° C), mais il est plus facile à mettre en oeuvre (pas de calibration, lecture des résultats linéaire etc.).

Il sera la “sonde” qui mesurera la température de l’eau dans le futur.

DSCF1265

Mon Arduino sait lire l’heure (DS1307)

DSCF1256 Arrivage d’Asie (Futurlec, une adresse à connaître !). Je reviendrai sur mes autres achats, mais ce qui m’a occupée aujourd’hui c’est une petite horloge “real time” basée sur la puce DS1307.

L’idée est que mon Arduino conserve la date et l’heure en permanence, histoire que les statistiques soient correctes.

DSCF1257

Voici la “bête” et sa référence chez  futurlec. J’ai dû me battre un peu avec les librairies DS1307 pour l’Arduino (il y a des modifications constantes), et surtout j’ai dû mettre un condensateur 10nf sur le circuit pour lisser le courant.

DSCF1262

Après quelques heures de tests et de programmation, mon Arduino sait lire (et garder !) l’heure, et encore mieux, l’afficher…

DSCF1259

Le résultat sur le port sériel (sera utilisé plus tard pour faire des statistiques sur PC), les données sont envoyées toutes les 10 secondes sur le port sériel.

DSCF1260

Le code actuel (je n’ai pas la prétention d’être une grande codeuse, alors à prendre “tel quel” ! Je commente beaucoup car j’ai peu de mémoire, alors c’est pour référence ultérieure. A noter que les pin 20 et 21 sont les ports one-wire sur l’Arduino Mega, ce sont les PIN 4 et 5 sur le modèle standard.

//**************** AquaControleur Test code ****************

//**************** Libraries ****************
#include <LiquidCrystal.h>
#include <EEPROM.h>
#include <Debounce.h>
#include <math.h>
#include <WProgram.h> //for the clock
#include <Wire.h> //for the clock
#include <DS1307.h> //for the clock

//**************** Defines PIN ****************
#define Ventilator 22
// Ventilator is put on Pin 22 – no PWM so far
// Temperature on analog 0 (no need to declare)
// SDA 20 //IC22 ports clock (no need to declare)
// SDC 21 //IC21 ports clock (no need to declare)

//Insert template for streaming
/*This allows you to write succinct code like
Serial << "My name is " << name << " and I am " << age << " years old.";
or
Serial << "GPS unit #" << gpsno << " reports lat/long of " << lat << "/" << long;*/
template<class T> inline Print &operator <<(Print &obj, T arg) {
obj.print(arg);
return obj;
}

//**************** LiquidCrystal display ****************
//rs on pin 12
//rw on pin 11
//enable on pin 10 d4, d5, d6, d7 on pins 5, 4, 3, 2 */
LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);

//**************** Other Variables ****************
//Temp Average calcs
const int NumberValuesAVG = 100; // Defines how many values the array will keep for the temp averages
double ReadingsAVG[NumberValuesAVG]; //array that contains the values
int index = 0;
double total = 0;
double average = 0;

//Temp values
#define ThermistorPIN 0   // Analog Pin 0 contains thermistor reading
double temp; //temperature var
double currentTemp = 0; //temporary Temp Variable
double HighLow[] = {
0,99,1};// HighLow[0]=High, HighLow[1]=low, HighLow[2]=AVG
double ventLimit[]  = {
26.0, 25.5}
; //first is the threshold to start vent, [0], second to stop vent [1]

//Date and Time Values
int rtc[7]; //real time clock values

//SerialPrint interval (set when we print to the serial port)
long LGpreviousMillis = 0;
long SHpreviousMillis = 0;

// Code Running intervals
long LGinterval = 10000; //interval at which the serial data is updated, here 10 secs
long SHinterval = 1000; //actions to run more often (every sec)

//**************** Thermistor Functions ****************
//Schematic:
// [Ground] —- [10k-Resister] ——-|——- [Thermistor] —- [+5v]
//                                     |
//                                Analog Pin 0
// using a 4.7K thermistor

// Inputs ADC Value from Thermistor and outputs Temperature in Celsius
//  requires: include <math.h>
// Utilizes the Steinhart-Hart Thermistor Equation:
//    Temperature in Kelvin = 1 / {A + B[ln(R)] + C[ln(R)]^3}
//    where A =0.0012819121, B = 0.00023789205 and C = 0.00000010217758
// Values for a,b,c taken from spec sheet here (p. 33 ) :: http://www.epcos.com/inf/50/db/ntc_06/LeadedDisks__B57164__K164.pdf then
// calculated from : http://www.capgo.com/Resources/Temperature/Thermistor/ThermistorCalc.html
//Thermistor code from http://www.arduino.cc/playground/ComponentLib/Thermistor2 (short code)

double Thermister(int RawADC) {
double Temp;
Temp = log(((10240000/RawADC) – 10000));
Temp = 1 / (0.0012819121 + (0.00023789205 * Temp) + (0.00000010217758 * Temp * Temp * Temp));
Temp = Temp – 273.15;            // Convert Kelvin to Celsius
//Temp = (Temp * 9.0)/ 5.0 + 32.0; // Convert Celcius to Fahrenheit
return Temp;
}

//RTC Functions

void printDec2(byte decVal)
{
if (decVal < 10)
Serial.print("0");
Serial.print(decVal, DEC);
}

void printLCDDec2(byte decVal)
{
if (decVal < 10)
lcd.print("0");
lcd.print(decVal, DEC);
}

void printDayName(byte d)
{
switch (d) {
case 1:
Serial.print("MON");
break;
case 2:
Serial.print("TUE");
break;
case 3:
Serial.print("WED");
break;
case 4:
Serial.print("THU");
break;
case 5:
Serial.print("FRI");
break;
case 6:
Serial.print("SAT");
break;
case 7:
Serial.print("SUN");
break;
default:
Serial.print("???");
}
}

// **************** SETUP ****************
void setup()
{
//Define the time — Uncomment to reset date/time (one-time operation)
/*RTC.stop();
RTC.set(DS1307_SEC,1);
RTC.set(DS1307_MIN,38);
RTC.set(DS1307_HR,17);
RTC.set(DS1307_DOW,7);
RTC.set(DS1307_DATE,19);
RTC.set(DS1307_MTH,07);
RTC.set(DS1307_YR,9);
RTC.start();*/

// start serial port at 9600 bps:
Serial.begin(9600);

//Clear Screen
lcd.clear();
lcd.home();
lcd << "Starting Up…" ;

//Init variables
pinMode (Ventilator, OUTPUT); //defines the ventilator is an output
HighLow[2] = Thermister(analogRead(0));

//Init RTC variables
for(int i=0; i<56; i++)
{
RTC.set_sram_byte(65,i);
}

}

// **************** LOOP ****************
void loop()
{

//**** TIME ****
RTC.get(rtc,true); // set the RTC

//Update time variables
byte sec = rtc[0];
byte min = rtc[1];
byte hour = rtc[2];
byte dow = rtc[3];
byte date = rtc[4];
byte month = rtc[5];
int year = rtc[6];

//**** TEMPERATURE ****
//Read Thermistor value
currentTemp = Thermister(analogRead(0));
//**** Actions do to in a short interval (here every 1 secs)

if (millis() – SHpreviousMillis > SHinterval) {
SHpreviousMillis = millis();

//print Temp on LCD
lcd.home();
lcd << "T:" << currentTemp << " ";
printLCDDec2(hour);
lcd.print (":");
printLCDDec2(min);
lcd.print (":");
printLCDDec2(sec);
//lcd << "T:" << currentTemp << " A:" << HighLow[2]; //temp & average
lcd.setCursor (0,1);
lcd << "L:" << HighLow[1] << " H:" << HighLow[0];
if (currentTemp < HighLow[1] )
{
HighLow[1] = currentTemp;
}
else if (currentTemp > HighLow[0]){

HighLow[0] = currentTemp;

}

}

//**** Actions with do every X seconds (defined by the Interval value  **** (here every 10 secs)
if (millis() – LGpreviousMillis > LGinterval) {
// save the last time serialPrint was done
LGpreviousMillis = millis();

//Calculate the AVG to avoid a calc that is too quick
//Average calculation
total= total – ReadingsAVG[index];
ReadingsAVG[index]= currentTemp;
total = total + ReadingsAVG[index];
index = index + 1;
//Calculates the AVG when the number of readings is reached
if (index >=NumberValuesAVG){
index = 0;
HighLow[2]=total/NumberValuesAVG;
}

//Print values on Serial for debugging & future logging on PC
// Prints the date
printDec2(hour);
Serial.print (":");
printDec2(min);
Serial.print (":");
printDec2(sec);
Serial.print (" ");
printDayName(dow);
Serial.print (" ");
printDec2(date);
Serial.print ("/");
printDec2(month);
Serial.print ("/");
Serial.print(year);

Serial << " |L " << HighLow[1] << " |H " << HighLow[0] <<" |C " << currentTemp << " |A " << HighLow[2];
Serial.println(" ");

if (currentTemp >= ventLimit[0] && digitalRead(Ventilator) == LOW){ //put Ventilator on if temp > 26 and if vent is off
digitalWrite(Ventilator, HIGH);
lcd.home();
lcd.clear();
lcd << "T:" << currentTemp << ">=LM:" << ventLimit[0] ;
lcd.setCursor (0,1);
lcd << "Vent Starting";
//printdate
printDec2(hour);
Serial.print (":");
printDec2(min);
Serial.print (":");
printDec2(sec);
Serial.print (" ");
printDayName(dow);
Serial.print (" ");
printDec2(date);
Serial.print ("/");
printDec2(month);
Serial.print ("/");
Serial.print(year);
Serial << " Temp : " << currentTemp << " Ventilator Starting";
Serial.println(" ");
}
else if (currentTemp <= ventLimit[1] && digitalRead(Ventilator) == HIGH) { // puts ventilator down if temp lower than 25.5 and if the vent is on
digitalWrite (Ventilator, LOW);
lcd.home();
lcd.clear();
lcd << "T:" << currentTemp << "<=LM:" << ventLimit[1] ;
lcd.setCursor (0,1);
lcd << "Vent Stopping";
//printdate
printDec2(hour);
Serial.print (":");
printDec2(min);
Serial.print (":");
printDec2(sec);
Serial.print (" ");
printDayName(dow);
Serial.print (" ");
printDec2(date);
Serial.print ("/");
printDec2(month);
Serial.print ("/");
Serial.print(year);
Serial << "Temp : " << currentTemp << " Ventilator Stopping";
Serial.println(" ");

}

}

}