[Débutant] Jardin hydroponique d'intérieur

Voila comment j'active ce relai :

//Déclaration pour sortie :
enum Sortie{On,Off};
//Fonction:
void BISTABLE(byte action)
  {if (action==Sortie(On))
     {digitalWrite(Bist_Pin_On,HIGH);BUZZER(500);
      digitalWrite(Bist_Pin_On,LOW);
     }
   else 
    { digitalWrite(Bist_Pin_Off,HIGH);BUZZER(50);delay(450);
      digitalWrite(Bist_Pin_Off,LOW);
    }
  delay(500); 
  }

Serge .D

iznobe:
ah ok :slight_smile: il se comporte comme un telerupteur en gros ? merci pour la precision .

Bonsoir
Pas exactement
un telerupteur cycle entre ON et OFF à chaque nouvelle commande , si tu ne connais d'une maniere ou d'une autre l'etat actuel, tu ne peux pas connaitre l'etat "à la prochaine commande"

Avec un relais bistable (une ou deux bobines) tu es certain de l'etat des sorties = fonction de la dernière commande
si le bistable est en position 1 et que tu commande un passage vers position 2 , il passera en position 2
si le bistable est en position 1 et que tu commande un passage vers position 1 , il restera en position 1

ok donc , c comme 2 relais separé , avec 1 alimentation par impulsion , un double inter domotisé plutot ?

Bon, j'ai cherché des modules RTC et j'hésite entre trois modèles :

  • le DS1302
  • le DS1307, mais je crois que c'est un double, en tous cas il semble plus compliqué.
  • et enfin le DS3231 que j'ai vu utilisé plusieurs fois sur des projets hydroponics.

Bien sûr le budget est important, mais avant tout ce qui m'intéresse c'est la facilité de mise en oeuvre, avec idéalement la librairie la plus populaire, pour trouver des tutos et de la doc à ma portée.
Qu'en pensez-vous ? Y a-t-il d'autres alternatives plus intéressantes que ces trois là ?

De préférence prendre le DS3231 qui est très stable sur le long terme.

Ok, merci, je le met dans mon panier ! J'ai trouvé un tuto pour la librairie et le code, ça a l'air assez simple finalement.

Cool ! J'ai enfin reçu les derniers éléments :

  • Carte 4 relais
  • Programmateur FDTI
  • Module RTC
  • Humidificateur ultrasons
  • Lampe de croissance
    Le Nano j'avais déjà, mais je vais prototyper sur Uno d'abord.

Je vais donc pouvoir attaquer le dur du projet !

J'avais posé la question plus haut, au niveau organisation du code. Est-ce que c'est mieux de créer des fichiers séparés qu'on retrouve en onglets dans l'INO où est-ce qu'il vaut mieux tout fourrer dans le fichier de base ? Sachant que aujourd'hui c'est un projet basique, mais que je le ferai évoluer plus tard, avec contrôle de l'ensoleillement, hygrométrie, etc.

Et comment procède-t-on d'ordinaire ? On fait le câblage puis on programme ou l'inverse ?

Bon, j'ai installé la librairie DS3231 et j'ai commencé à coder :

//Fichier global de configuration
#include <Wire.h>
#include <ds3231.h>

struct ts t;

void setup() {
  Serial.begin(9600);
  Wire.begin();
  DS3231_init(DS3231_INTCN);
  boolean vNuit = false; 
}

// Mise à jour de la variable nocturne;

void loop() {
  boolean vNuit;
  if (t.hour > 6) {
    if (vNuit = true) {
      vNuit = false;
      // action de nuit
    }
  }
  else {
    if (vNuit = false);
    {
      vNuit = true;
      // action de jour
    }
  }
  //Monitoring RTC  
  DS3231_get(&t);
  Serial.print("date : ");
  Serial.print(t.mday);
  Serial.print("/");
  Serial.print(t.mon);
  Serial.print("/");
  Serial.print(t.year);
  Serial.print("\t Heure : ");
  Serial.print(t.hour);
  Serial.print(":");
  Serial.print(t.min);
  Serial.print(".");
  Serial.println(t.sec);
 if (vNuit)
 Serial.println("Cycle nocturne");
else
 Serial.println("Cycle diurne");
 // Pause 1mn
  delay(60000);
}

Je ne sais pas trop bien ce que je fais... En tous cas, le moniteur affiche la bonne heure ainsi que "Cycle nocturne" ce qui est déjà une bonne chose. Je laisse tourner cette nuit pour voir si à 6h ça bascule en "Cycle diurne".
Si ça marche, ça voudra dire que je n'aurais plus qu'à ouvrir ou fermer des ports pour commander les relais.

Si mon code est pourri, n'hésitez pas dire pourquoi.

Tu vas avoir un petit problème.

if (t.hour > 6) {
    if (vNuit = true) {
      vNuit = false;
      // action de nuit
    }
  }
  else {
    if (vNuit = false);
    {
      vNuit = true;
      // action de jour
    }
  }

Pour tester une égalité il faut utiliser ==.
= tout seul est l'opérateur d'affectation.

if (vNuit = false);
    {
      vNuit = true;
      // action de jour
    }

Il ne faut pas mettre un ; après le if sinon le code qui est derrière est toujours exécuté. Il faut écrire comme cela:

if (vNuit = false)
    {
      vNuit = true;
      // action de jour
    }

vNuit est défini localement dans loop() mais est appelé dans setup() cela doit générer une erreur de compilation.
Tu ne seras en mode nuit que de 0h00 à 6h59.

Merci pour ta réponse fdufnews, il y a des choses que je comprends déjà mieux.

_"Pour tester une égalité il faut utiliser =="
Merci, c'est corrigé ! Lors du test de cette nuit, ça a eu l'air de fonctionner quand même. D'ailleurs, est ce que (vNuit == true) est nécessaire, n'est-ce pas plus "propre" d'avoir if (vNuit) ?

_"vNuit est défini localement dans loop() mais est appelé dans setup() cela doit générer une erreur de compilation."
En fait, je voulais que ça soit une variable globale (en vue d'autres applications), du coup je l'ai déclarée (bêtement?) dans setup(), ensuite je pensais qu'il fallait aussi la rappeler dans la fonction loop(). Pas d'erreur de compilation curieusement...
Au contraire (et c'est pourquoi je l'ai rappelée aussi dans loop() ) si je met la ligne en commentaire j'ai une série d'erreurs qui apparaissent :

Greenz_V1_0.ino: In function ‘void setup()’:
Greenz_V1_0.ino:17:11: warning: unused variable ‘vNuit’ [-Wunused-variable]
Greenz_V1_0.ino: In function ‘void loop()’:
Greenz_V1_0.ino:25:9: error: ‘vNuit’ was not declared in this scope
Greenz_V1_0.ino:31:9: error: ‘vNuit’ was not declared in this scope
Greenz_V1_0.ino:50:6: error: ‘vNuit’ was not declared in this scope

Du coup, dans l'attente de savoir comment mieux utiliser cette variable, j'ai laissé ce qui semble fonctionner...

_ "Il ne faut pas mettre un ; après le if sinon le code qui est derrière est toujours exécuté."
Coup de bol, le ; de trop était en fin de test de conditon, donc ça a bien basculé en "cycle diurne" à... 7h !

_"Tu ne seras en mode nuit que de 0h00 à 6h59."
Ça fait une heure de plus que prévu, j'ai mis ">5" du coup, ça fera bien un cycle nuit de 6h. Merci, j'ai compris que les minutes ne comptent pas dans ce test.

Voici l'état actuel du code :

//Fichier global de configuration

//Le script est écrit pour un système hydroponique.
//Il définit à terme un cycle nocturne (rupture d'éclairage + brumisation) et un cycle diurne (éclairage seul)
//Un test des réserves d'eau est prévu, avec alarme le cas échéant.


#include <Wire.h>
#include <ds3231.h>

struct ts t;

void setup() {
  Serial.begin(9600);
  Wire.begin();
  DS3231_init(DS3231_INTCN);
  boolean vNuit = false; 
}

// Mise à jour de la variable nocturne;

void loop() {
  boolean vNuit;
  if (t.hour > 5) {
    if (vNuit == true) {
      vNuit = false;
      // action de nuit (non implantée actuellement)
    }
  }
  else {
    if (vNuit == false) {
      vNuit = true;
      // action de jour (non implantée actuellement)
    }
  }
  //Monitoring RTC  
  DS3231_get(&t);
  Serial.print("date : ");
  Serial.print(t.mday);
  Serial.print("/");
  Serial.print(t.mon);
  Serial.print("/");
  Serial.print(t.year);
  Serial.print("\t Heure : ");
  Serial.print(t.hour);
  Serial.print(":");
  Serial.print(t.min);
  Serial.print(".");
  Serial.println(t.sec);
 if (vNuit)
 Serial.println("Cycle nocturne...");
else
 Serial.println("Cycle diurne...");
 // Pause 1mn
  delay(60000);
}

Bon, j'avance dans le code. Maintenant les relais sont pilotés et le cycle se fait bien. Le truc curieux avec le module 4 relais, c'est qu'il semble inversé. Quand la pin de l'Arduino est HIGH, la LED témoin s'éteint et le relais passe en repos. C'est pas grave en soi, j'inverse la sortie, voila tout. Mais c'est étrange tout de même...

//Fichier global de configuration

//Le script est écrit pour un système hydroponique.
//Il définit à terme un cycle nocturne et un cycle diurne, avec au début de chaque cycle des actions spécifiques.
//Un test des réserves d'eau est prévu, avec alarme le cas échéant.


#include <Wire.h>
#include <ds3231.h>

boolean vNuit = true;

int brumisateurPin = 2;
int ventilateurPin = 3;
int lampePin = 4;
int bulleurPin = 5;

struct ts t;

void setup() {
  Serial.begin(9600);
  Wire.begin();
  DS3231_init(DS3231_INTCN);
  pinMode(brumisateurPin, OUTPUT); 
  pinMode(ventilateurPin, OUTPUT);
  pinMode(lampePin, OUTPUT);
  pinMode(bulleurPin, OUTPUT);
  
}

// Mise à jour de la variable nocturne;

void loop() {
  boolean vNuit;
  if (t.hour > 5) {
    if (vNuit == true) {                    // Cycle diurne
        vNuit = false;
    }
  }
  else {
    if (vNuit == false) {                   // Cycle nocturne   
        vNuit = true;
      }
    }
  //Monitoring RTC  
  DS3231_get(&t);
  Serial.print("date : ");
  Serial.print(t.mday);
  Serial.print("/");
  Serial.print(t.mon);
  Serial.print("/");
  Serial.print(t.year);
  Serial.print("\t Heure : ");
  Serial.print(t.hour);
  Serial.print(":");
  Serial.print(t.min);
  Serial.print(".");
  Serial.println(t.sec);
  
  if (vNuit){
    Serial.println("Cycle nocturne...");
    digitalWrite(brumisateurPin, HIGH);   
    digitalWrite(ventilateurPin, LOW);    
    digitalWrite(lampePin, LOW);         
    digitalWrite(bulleurPin, LOW);
  }
  else {
    Serial.println("Cycle diurne...");
    digitalWrite(brumisateurPin, LOW);    
    digitalWrite(ventilateurPin, HIGH);    
    digitalWrite(lampePin, HIGH);  
    digitalWrite(bulleurPin, HIGH);
  }
  // Pause 1mn
  delay(60000);
}

Autre chose, je comptais utiliser les pins 1,2,3,4, pour les relais correspondants, mais il semble que le RTC envoie une impulsion sur la pin 1 toutes les 1s. La led TX suit l'impulsion et le diagrame de la carte indique TX->1. Ca doit sans doute être normal, mais je ne comprends pas bien l'intérêt du truc vu que ça bouffe une sortie...

Tu n'as pas bien compris comment fonctionne la définition des variables et leur portée.
Dans ton code

#include <ds3231.h>

boolean vNuit = true;

int brumisateurPin = 2;
int ventilateurPin = 3;
int lampePin = 4;
int bulleurPin = 5;

struct ts t;


// Mise à jour de la variable nocturne;

void loop() {
  boolean vNuit;
  if (t.hour > 5) {
    if (vNuit == true) {                    // Cycle diurne
        vNuit = false;

La variable vNuit déclarée au tout début du programme est vue de toutes les fonctions de ton programme
La variable vNuit que tu définies dans loop() n'est visible que de l'intérieur de loop() ET elle masque la varaible globale homonyme.
Si tu veux avoir une variable vNuit visible de partout et modifiable partout (y compris dans loop) il faut supprimer la déclaration dans loop()

Salut fdufnews,
Oui, je comprends bien ce que tu m'explique. Je ne sais pas pourquoi j'avais eu les erreurs de compilation en commentant la ligne en question dans void loop() la dernière fois, ce qui m'avait poussé à la laisser. Cette fois, pas de souci, j'ai supprimé la déclaration de variable dans la boucle, et il n'y a plus d'erreur. Merci.
Donc, si j'ai bien compris, il suffit de déclarer al variable en tête de programme pour qu'elle devienne globale. Et ça marche quel que soit le type de variable : avec boolean comme avec int. C'est bien ça ?

Autre question, j'ai essayé sans succès :

vNuit = !vNuit;

C'est du détail car ça marche très bien avec true/false, mais je n'ai pas compris où je faisais une erreur de syntaxe ?

Et voici le code au propre :

//Fichier global de configuration

//Le script est écrit pour un système hydroponique.
//Il définit à terme un cycle nocturne et un cycle diurne, avec au début de chaque cycle des actions spécifiques.
//Un test des réserves d'eau est prévu, avec alarme le cas échéant.


#include <Wire.h>       //Appel de la libraire permettant la communication avec l'horloge temps reel
#include <ds3231.h>     //Appel de la librairie de l'horloge temps réel.

boolean vNuit = true;   //Variable stockant l'état du cycle jour/nuit

int brumisateurPin = 2; //Pin connectée au Relais#1 commandant le brumisateur 5v
int ventilateurPin = 3; //Pin connectée au Relais#2 commandant le ventilateur 2v 
int lampePin = 4;       //Pin connectée au Relais#3 commandant la lampe de croissance AC 
int bulleurPin = 5;     //Pin connectée au Relais#4 commandant la pompe à air AC

struct ts t;            //Rappel de l'horloge temps réel.

void setup() {

//Initialisation de la communication avec l'horloge temps réel  
  Serial.begin(9600);
  Wire.begin();
  DS3231_init(DS3231_INTCN);
  
//Déclaration des sorties utilisées
  pinMode(brumisateurPin, OUTPUT); 
  pinMode(ventilateurPin, OUTPUT);
  pinMode(lampePin, OUTPUT);
  pinMode(bulleurPin, OUTPUT);
  
}


void loop() {
  
// Mise à jour de la variable nocturne;
  if (t.hour > 5) {
    if (vNuit == true) {   // Cycle diurne
        vNuit = false;
    }
  }
  else {
    if (vNuit == false) {  // Cycle nocturne   
        vNuit = true;
      }
    }

// Visualisation de l'horloge temps réel
  DS3231_get(&t);
  Serial.print("date : ");
  Serial.print(t.mday);
  Serial.print("/");
  Serial.print(t.mon);
  Serial.print("/");
  Serial.print(t.year);
  Serial.print("\t Heure : ");
  Serial.print(t.hour);
  Serial.print(":");
  Serial.print(t.min);
  Serial.print(".");
  Serial.println(t.sec);
  
//Commandes de cycles   
  if (vNuit){
    Serial.println("Cycle nocturne...");
    digitalWrite(brumisateurPin, HIGH);   
    digitalWrite(ventilateurPin, LOW);    
    digitalWrite(lampePin, LOW);         
    digitalWrite(bulleurPin, LOW);
  }
  else {
    Serial.println("Cycle diurne...");
    digitalWrite(brumisateurPin, LOW);    
    digitalWrite(ventilateurPin, HIGH);    
    digitalWrite(lampePin, HIGH);  
    digitalWrite(bulleurPin, HIGH);
  }
  
// Délai entre chaque test
  delay(60000);
}

N'hésitez pas à me dire si l'on peut simplifier le code ou si une autre méthode de gestion serait plus appropriée.

Laurel_et_Ardui:
Autre question, j'ai essayé sans succès :

vNuit = !vNuit;

C'est du détail car ça marche très bien avec true/false, mais je n'ai pas compris où je faisais une erreur de syntaxe ?

Cette écriture est correcte et compile sans problème. Tu devais avoir un autre problème.

Merci pour ta réponse. Bon, et bien ça reste un grand mystère car avec true/false tout fonctionne et en remplaçant juste avec !vNuit ça ne marche plus... Peut être une question de version d'Arduino ou de l'IDE, va savoir...

Je m'attaque maintenant au hardware, au cabinet, etc.

Laurel_et_Ardui:
Bon, j'avance dans le code. Maintenant les relais sont pilotés et le cycle se fait bien. Le truc curieux avec le module 4 relais, c'est qu'il semble inversé. Quand la pin de l'Arduino est HIGH, la LED témoin s'éteint et le relais passe en repos. C'est pas grave en soi, j'inverse la sortie, voila tout. Mais c'est étrange tout de même...

Bonjour;

Cela ne me semble pas complétement illogique, ca dépend du schéma de la carte relais.
Et comme tu dis, on peut inverser les sorties.

Par contre il faut tout de même penser à un truc tout bête:
Il vaut mieux qu'au repos, c'est à dire relais inactivé (ou carte arduino éteinte) les contacts de tes relais ne risque pas l'alimenter quoi que se soit.

Exemple.

Ta carte arduino est éteinte (car ton alim par exemple à flanchée), les sorties de la carte arduino sont donc à l'état bas, tu constate que les relais sont commandés (car il sont commandé par un état bas), et si tu a utilisé le contact Normalement Ouvert de ton relais (ouvert quand il est au repos) alors il va se fermer, et tu va alimenter quelque chose que tu ne gère plus par le soft car il est à l'arrêt.

C'est juste un aspect sécurité qui se gére en hard et auquel on ne pense pas toujours.

Merci jeanfranlec pour ton intervention. Effectivement, c'est un truc auquel je n'ai pas pensé. Donc je vais inverser le câblage des relais et le code. Donc "ON" se fera avec

digitalWrite(ventilateurPin, LOW);

Ça fait un peu bizarre dans le code, mais je mettrais un commentaire pour me souvenir. C'est plus sûr en effet, surtout si je suis en déplacement.

Je me suis surement mal exprimé.

Je voulais dire qu'il faudrait mieux qu'au repos, carte arduino à l'arrêt (éteinte, hors tension, ...), être sur que les contacts des relais qui sont utilisés soient ouvert.

Effectivement, tu ne vas peut-être pas utiliser que les alim dispo sur arduino pour alimenter tes actionneurs, notamment tout ce qui est en AC, donc si la carte arduino est à l'arrêt pour une raison quelconque (non alimentée) il ne faudrait pas que des contacts relais qui seraient fermés dans ce cas, puisse alimenter des actionneurs.

Enfin, ce n'est pas une obligation absolue, juste un conseil.

Oui, oui, c'est bien comme ça que je l'avais compris. Et c'est un excellent conseil. Juste comme la carte semble "inversée", il faut une information LOW pour mettre le relais sous tension.

Laurel_et_Ardui:
Merci jeanfranlec pour ton intervention. Effectivement, c'est un truc auquel je n'ai pas pensé. Donc je vais inverser le câblage des relais et le code. Donc "ON" se fera avec

digitalWrite(ventilateurPin, LOW);

Ça fait un peu bizarre dans le code, mais je mettrais un commentaire pour me souvenir. C'est plus sûr en effet, surtout si je suis en déplacement.

Pour gérer ce genre de problème, il faut utiliser les facilités du langage

#define RELAIS_FERME LOW
#define RELAIS_OUVERT HIGH

    digitalWrite(ventilateurPin, RELAIS_FERME)