potager connecté // gestion arrosage et lumiere avec ephemeris et RTC

Bonjour à tous,

Je travaille sur un projet de potager connecté avec un arrosage automatique et la gestion d'une lampe de croissance calé sur le levé et couché du soleil (pas de lumiere du jour à l'endroit ou sera installé le potager).

Materiel :

  • Arduino Uno
  • Relais lumiere
  • Relais pompe
  • module RTC 1302
  • bibliotheque Wire
  • bibliotheque RTC lib
  • bibliotheque ephemeris

allumage et extinction des relais ok mais je ne parviens pas à declencher le relais lumiere en me calant sur l'horaire de levé du soleil fourni par ephemeris.

Ma demarche est la suivante :
Si l'heure RTC est superieur ou egale à l'horaire "levé du soleil" alors allume le relais lumiere.
puis
Si l'heure RTC est superieur ou egale à l'heure "couché du soleil" alors eteint le relais lumiere.

novice dans le développement, je ne parviens pas à mettre tout ca en place... Si vous avez quelques pistes ou conseils, je suis preneur

Merci d'avance

#include <Wire.h> // bibliotheque Wire (RTC)
#include "RTClib.h" //bibliotheque module RTC
#include <Ephemeris.h> // bibliotheque ephemeris

RTC_DS1307 rtc;

int PinHumidite = 0; // capteur d'humidité.
int humid; // variable humidité
int pinRelais = 4; //variable pour le pin qui commande le relais



//debut ephemeris
void printDate(int day, int month, int year)
{
  Serial.print(day);
  Serial.print("/");
  Serial.print(month);
  Serial.print("/");
  Serial.print(year);
}

void printRiseAndSet(char *city, FLOAT latitude, FLOAT longitude, int UTCOffset, int day, int month, int year, char *ref)
{
  Ephemeris::setLocationOnEarth(latitude, longitude);

  Serial.print(city);
  Serial.print(" (UTC");
  if ( UTCOffset >= 0 )
  {
    Serial.print("+");
  }
  Serial.print(UTCOffset);
  Serial.print(")");
  Serial.println(":");

  SolarSystemObject sun = Ephemeris::solarSystemObjectAtDateAndTime(Sun,
                          day, month, year,
                          0, 0, 0);

  // Print sunrise and sunset if available according to location on Earth
  if ( sun.riseAndSetState == RiseAndSetOk )
  {
    int hours, minutes;
    FLOAT seconds;

    // Convert floating hours to hours, minutes, seconds and display.
    Ephemeris::floatingHoursToHoursMinutesSeconds(Ephemeris::floatingHoursWithUTCOffset(sun.rise, UTCOffset), &hours, &minutes, &seconds);
    Serial.print("  Sunrise: ");
    Serial.print(hours);
    Serial.print("h");
    Serial.print(minutes);
    Serial.print("m");
    Serial.print(seconds, 0);
    Serial.println("s");

    // Convert floating hours to hours, minutes, seconds and display.
    Ephemeris::floatingHoursToHoursMinutesSeconds(Ephemeris::floatingHoursWithUTCOffset(sun.set, UTCOffset), &hours, &minutes, &seconds);
    Serial.print("  Sunset:  ");
    Serial.print(hours);
    Serial.print("h");
    Serial.print(minutes);
    Serial.print("m");
    Serial.print(seconds, 0);
    Serial.println("s");
  }
  else if ( sun.riseAndSetState == LocationOnEarthUnitialized )
  {
    Serial.println("You must set your location on Earth first.");
  }
  else if ( sun.riseAndSetState == ObjectAlwaysInSky )
  {
    Serial.println("Sun always in sky for your location.");
  }
  else if ( sun.riseAndSetState == ObjectNeverInSky )
  {
    Serial.println("Sun never in sky for your location.");
  }

  Serial.print("  Ref: ");
  Serial.println(ref);
  Serial.println();
}
//fin ephemeris



void setup() {
  // debut mise en place du temps
  while (!Serial); // for Leonardo/Micro/Zero

  Serial.begin(9600);
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }

  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }
  // fin mise en place du temps

  // debut temps en test
  DateTime now = rtc.now();
  DateTime heureRTC;

  uint8_t heureAlarme = 13;
  uint8_t minuteAlarme = 54;
  uint16_t jourAlarme = 21;
  uint16_t moisAlarme = 3;

  heureRTC = rtc.now();

  if (heureRTC.hour() == heureAlarme && heureRTC.minute() == minuteAlarme && heureRTC.day() == jourAlarme && heureRTC.month() == moisAlarme) {
    digitalWrite(13, HIGH);
    Serial.print("fonctionne !!");
  } else {
    digitalWrite(13, HIGH);
  }
  Serial.println();
  delay(1000);

  // fin temps en test


  //debut ephemeris

  {
    Serial.begin(9600);

    int day = heureRTC.day(), month = heureRTC.month(), year = heureRTC.year();

    Serial.print("SunRise/SunSet at ");
    printDate(day, month, year);
    Serial.println(":\n");

    //               CITY         LATITUDE    LONGITUDE     TZ   DATE             REFERENCE
    printRiseAndSet("Paris",      48.856614,    2.3522219,  +1,  day, month, year, "sunearthtools (10/2/2017): SunRise: 08:07:00 | SunSet: 18:03:19");

  }

  //fin ephemeris



  pinMode(pinRelais, OUTPUT); //pin lampe en mode OUTPUT
  Serial.begin(9600);
  pinMode(PinHumidite, INPUT); // capteur
  pinMode(2, OUTPUT); // relais
  digitalWrite(2, LOW); // pompe off

}

void loop() {





  // arrosage
  humid = analogRead(PinHumidite); // lecture capteur humidité
  Serial.println(humid); //affichage humidité

  if (humid < 800) // si sol sec (eau : 860, air : 0, terre "à arroser" : 840 terre seche : 185 )
  {
    digitalWrite(2, HIGH); // allumage pompe
    Serial.println("pompe arrosage on");
    delay(1000); // arrosage 10 secondes
    digitalWrite(2, LOW); // arret pompe
    Serial.println("pompe off");
  }

  // allumage de la lampe
  digitalWrite(pinRelais, HIGH); // on commande l'allumage
  Serial.println("lumiere on");
  delay(3000);
  digitalWrite(pinRelais, LOW); // on commande l'extinction
  Serial.println("lumiere off");
  delay(1000);




  Serial.println("pause");
  delay(1000); // pause 10mns le temps que l'eau se diffuse autour du capteur
  //delay(1000); // pause


}

Ma demarche est la suivante :
Si l'heure RTC est supérieure ou egale à l'horaire "levé du soleil" alors allume le relais lumiere.
puis
Si l'heure RTC est superieure ou egale à l'heure "couché du soleil" alors eteint le relais lumiere.

on ne voit pas ça dans le code de la loop()...

en faisant     rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));vous changez l'heure de votre RTC à chaque reboot de l'Arduino (elle se met en gros à l'heure de la dernière compilation du code)

vous avez deux fois Serial.begin(9600);
...

vous devriez pour le moment mettre votre culture que la police ne doit pas voir :sunglasses: :grin: :smiling_imp: de côté et vous concentrer juste sur la gestion de la RTC et de la classe DateTime

il y a exemple dans la libraire je suppose...

(notez qu'une DS1307 n'est pas du tout précise et va fortement dériver, préférez une DS3231)

naskaone:
mais peut etre que la ciboulette est devenue illegale ?! :smiley:

vous la faites poussez jusqu'à ce qu'on ne voit plus le commissariat et vous pouvez la ramasser :slight_smile:

le code qui force l'heure de compilation l'idée c'est de compiler une fois, charger et faire tourner le code --> ça règle l'heure. puis vous commentez cette ligne, recompilez et rechargez le code et là vous avez maintenant l'horloge à la bonne heure ET un code qui ne la change pas à chaque reboot dans votre arduino

si vous avez le wifi à la maison, vous devriez partir sur un ESP au lieu d'un arduino "standard" car il pourra obtenir l'heure exacte d'un serveur de temps pour remettre à jour la RTC. en plus si vous codez un peu, vous pourrez interrogez votre système pour savoir si tout va bien et afficher des infos sur votre PC ou smartphone

naskaone:
Materiel :

  • Arduino Uno
  • Relais lumiere
  • Relais pompe
  • module RTC 1302
  • bibliotheque Wire
  • bibliotheque RTC lib
  • bibliotheque ephemeris

bonsoir
Juste sur ce point, pour faire une levée de doute et t'eviter de trop "galerer"
Le module RTC que tu a en main est basé sur un DS1302 ou un DS1307 ? 8)

oui j'ai vu l'erreur lol c'est bien le 1307 :wink:

Salut à tous,

Bon finalement sur les conseils de J-M-L, je me suis concentré sur quelque chose de plus simple pour l'instant.

  • un arrosage declenché à 6h (avant l'allumage de la lampe).
  • allumage de la lumiere de 7h à 19h puis extinction.

Le code est ci-dessous, si vous avez des remarques pour l'optimiser ou améliorer des choses, il a le merite de fonctionner mais pour vos yeux averti j'imagine que ca reste de la bidouille.

---amélioration envisagées :

  • capteur de temperature
  • ecran LCD pour indiquer la temperature et/ou le nombre de boucles d'arrosage dans la journée.
  • possibilité de changer les parametres (horaires, temps d'arrosage) via internet ou un smartphone
  • prise d'une photo par jour pour voir l'evolution des plantes en cas d'absence.
  • possibilité de demultiplier les cultures (plusieurs capteurs d'humidité, arrosage geré separement...)
    -capteur de niveau d'eau pour le reservoir
    ...

:smiley:

//time
/* Dépendances */
#include <Wire.h>
#include "DS1307.h"

/* Rétro-compatibilité avec Arduino 1.x et antérieur */
#if ARDUINO >= 100
#define Wire_write(x) Wire.write(x)
#define Wire_read() Wire.read()
#else
#define Wire_write(x) Wire.send(x)
#define Wire_read() Wire.receive()
#endif

/** Fonction de conversion BCD -> decimal */
byte bcd_to_decimal(byte bcd) {
  return (bcd / 16 * 10) + (bcd % 16);
}

/** Fonction de conversion decimal -> BCD */
byte decimal_to_bcd(byte decimal) {
  return (decimal / 10 * 16) + (decimal % 10);
}

/**
   Fonction récupérant l'heure et la date courante à partir du module RTC.
   Place les valeurs lues dans la structure passée en argument (par pointeur).
   N.B. Retourne 1 si le module RTC est arrêté (plus de batterie, horloge arrêtée manuellement, etc.), 0 le reste du temps.
*/
byte read_current_datetime(DateTime_t *datetime) {

  /* Début de la transaction I2C */
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire_write((byte) 0); // Lecture mémoire à l'adresse 0x00
  Wire.endTransmission(); // Fin de la transaction I2C

  /* Lit 7 octets depuis la mémoire du module RTC */
  Wire.requestFrom(DS1307_ADDRESS, (byte) 7);
  byte raw_seconds = Wire_read();
  datetime->seconds = bcd_to_decimal(raw_seconds);
  datetime->minutes = bcd_to_decimal(Wire_read());
  byte raw_hours = Wire_read();
  if (raw_hours & 64) { // Format 12h
    datetime->hours = bcd_to_decimal(raw_hours & 31);
    datetime->is_pm = raw_hours & 32;
  } else { // Format 24h
    datetime->hours = bcd_to_decimal(raw_hours & 63);
    datetime->is_pm = 0;
  }
  datetime->day_of_week = bcd_to_decimal(Wire_read());
  datetime->days = bcd_to_decimal(Wire_read());
  datetime->months = bcd_to_decimal(Wire_read());
  datetime->year = bcd_to_decimal(Wire_read());

  /* Si le bit 7 des secondes == 1 : le module RTC est arrêté */
  return raw_seconds & 128;
}

/**
   Fonction ajustant l'heure et la date courante du module RTC à partir des informations fournies.
   N.B. Redémarre l'horloge du module RTC si nécessaire.
*/
void adjust_current_datetime(DateTime_t *datetime) {

  /* Début de la transaction I2C */
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire_write((byte) 0); // Ecriture mémoire à l'adresse 0x00
  Wire_write(decimal_to_bcd(datetime->seconds) & 127); // CH = 0
  Wire_write(decimal_to_bcd(datetime->minutes));
  Wire_write(decimal_to_bcd(datetime->hours) & 63); // Mode 24h
  Wire_write(decimal_to_bcd(datetime->day_of_week));
  Wire_write(decimal_to_bcd(datetime->days));
  Wire_write(decimal_to_bcd(datetime->months));
  Wire_write(decimal_to_bcd(datetime->year));
  Wire.endTransmission(); // Fin de transaction I2C
}

#include <Wire.h>
#include <RTClib.h>

//Variables mise à jour Horloge
byte TabMaH[6] = {17, 1, 1, 0, 0, 0};
byte MaH; int BpH; byte DrapH; byte SelH; byte ColH; byte MaxH; byte MinH; byte CurH; byte CurligH;

// Variables mise à jour de la plage horaire
int Bp; int MaJ; int Flag; int Vo; int Lig; int Sel; ; int Col; int Val; int Max; int Cur; int CurLig;
// Table Evénerments chaque ligne correspond à une voie. Sur la ligne, on trouve H départ, M Départ, H Arrêt, M Arrêt..
int TabEvt [6][4] =
{
  {14, 0, 14, 1},
  {14, 1, 14, 2},
  {14, 2, 14, 3},
  {14, 3, 14, 4},
  {25, 0, 0, 0},
  {25, 0, 0, 0}
};
byte PinSorties[6] = {17, 16, 11, 12, 2, 3};
//time

int PinHumidite = 0; // capteur d'humidité.
int humid; // variable humidité
int pinRelais = 4; //variable pour le pin qui commande le relais

void setup() {

  //time
  /* Initialise le port série */
  Serial.begin(115200);

  /* Initialise le port I2C */
  Wire.begin();

  /* Vérifie si le module RTC est initialisé */
  DateTime_t now;
  if (read_current_datetime(&now)) {
    Serial.println(F("L'horloge du module RTC n'est pas active !"));

    // Reconfiguration avec une date et heure en dure (pour l'exemple)
    now.seconds = 0;
    now.minutes = 0;
    now.hours = 12; // 12h 0min 0sec
    now.is_pm = 0;
    now.day_of_week = 4;
    now.days = 1;
    now.months = 12;
    now.year = 16; // 1 dec 2016
    adjust_current_datetime(&now);
  }

  //time

  pinMode(pinRelais, OUTPUT); //pin lampe en mode OUTPUT
  digitalWrite(pinRelais, LOW); // lumiere off
  Serial.begin(115200);
  pinMode(PinHumidite, INPUT); // capteur
  pinMode(2, OUTPUT); // relais
  digitalWrite(2, LOW); // pompe off

}

void loop() {

  //time
  //Lit la date et heure courante
  DateTime_t now;
  if (read_current_datetime(&now)) {
    Serial.println(F("L'horloge du module RTC n'est pas active !"));
  }

  //Affiche la date et heure courante
  Serial.print(F("Date : "));
  Serial.print(now.days);
  Serial.print(F("/"));
  Serial.print(now.months);
  Serial.print(F("/"));
  Serial.print(now.year + 2000);
  Serial.print(F("  Heure : "));
  Serial.print(now.hours);
  Serial.print(F(":"));
  Serial.print(now.minutes);
  Serial.print(F(":"));
  Serial.println(now.seconds);

  //Rafraichissement une fois par seconde
  delay(1000);
  //time

  // test arrosage

  if (now.hours >= 6 && now.hours <= 7)
  {
    humid = analogRead(PinHumidite); // lecture capteur humidité
    Serial.println(humid); //affichage humidité

    if (humid < 800) // si sol sec (eau : 860, air : 0, terre "à arroser" : 840 terre seche : 185 )
    {
      digitalWrite(2, HIGH); // allumage pompe
      Serial.println("pompe arrosage on");
      delay(1000); // arrosage 10 secondes
      digitalWrite(2, LOW); // arret pompe
      Serial.println("pompe arrosage off");
    }
  }

  //Serial.println("pause");
  delay(1000); // pause 10mns le temps que l'eau se diffuse autour du capteur
  //delay(1000); // pause

  //test lampe

  if (now.hours >= 7 && now.hours <= 19)
  {
    digitalWrite(pinRelais, HIGH); // on commande l'allumage
    Serial.println("lumiere on");
  }
  else
  {
    digitalWrite(pinRelais, LOW); // on commande l'extinction
    Serial.println("lumiere off");
  }
  delay(18000);

}

Bonjour,
Si je peux me permettre, la DS3231 est plus performante (précise) que la DS1307. Elle a un quartz intégré et une compensation en température.

oui, c'est ce qu'on m'a dit, mais j'ai deja acheté un 1307, donc pour le moment je vais faire avec et le remplacer par la suite. :wink:

question est ce que tu as acces a internet la ou sera ta serre? par wifi ou bluetooth?

Le mieux c'est de prendre un ESP32, et de caler l'heure d'internet...

Moi j'ai un potager connecté acheter dans le commerce, c'est genial, tu regle l'intensité de la lumiere, tu regle l'heure ensoleillement

Bonjour, comprenez vous toutes les fonctions que vous avez en début de code? (bcd_to_decimal(), decimal_to_bcd(), read_current_datetime(), ...)

--> si vous ne les comprenez pas, autant prendre une librairie qui va vous simplifier grandement la vie et votre code pour démarrer...

avec une DS1307 ou DS3231 vous pouvez utiliser la librairie RTClib

Ensuite pour tester si le moment courant est entre deux instants bien définis de la journée, il suffit de calculer le nombre de secondes depuis minuit et de comparer

voici à quoi pourrait ressembler un code qui teste si on est entre 8h15 et 19h22 chaque jour et au moment de la bascule, effectuer une action

#include <Wire.h>
#include "RTClib.h"

RTC_DS1307 rtc;

// on définit l'heure de début et de fin en comptant le nombre de secondes depuis minuit
const uint32_t debut =  8 * 3600ul + 15 * 60ul + 0 ; // 08:15:00
const uint32_t fin   = 19 * 3600ul + 22 * 60ul + 0 ; // 19:22:00

bool systememActif = false;

void setup()
{
  Serial.begin(115200);
  if (! rtc.begin()) {
    Serial.println(F("Horloge absente"));
    while (true); // on s'arrête
  }

  if (! rtc.isrunning()) {
    Serial.println(F("Initialiser la RTC !!"));
    // pour mettre la date 1 fois, décommenter une des lignes en fonction de ce que vous voulez
    // chargez et faite tourner le code puis commentez à nouveau la ligner et rechargez le code
    // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // pour mettre à la date de dernière compilation
    // rtc.adjust(DateTime(2019, 3, 24, 10, 0, 0)); // pour mettre à 24 mars 2109 à 10h du matin
  }
}

void loop()
{
  DateTime maintenant = rtc.now();
  // ------------------------------------------------------------------
  // la classe DateTime vous permet d'interroger le moment présent par:
  //    ** année dans maintenant.year()
  //    ** mois dans maintenant.month()
  //    ** jour dans maintenant.day()
  //    ** heure dans maintenant.hour()
  //    ** minute dans maintenant.minute()
  //    ** seconde dans maintenant.second()
  // ------------------------------------------------------------------

  uint32_t moment = maintenant.hour() * 3600ul + maintenant.minute() * 60ul + maintenant.second() ; // nombre de secondes depuis minuit


  if ((moment >= debut) && (moment <= fin)) {  // est-on entre 8h15 et 19h22 ?
    if (!systememActif) {    // si oui, vient-on d'activer le système ?
      Serial.println(F("Allumage"));
      // >>>>>>> ici allumer ce que vous voulez <<<<<<<<<<
      systememActif = true; // on mémorise que l'on vient d'allumer le système
    }
  } else {
    if (systememActif) {
      Serial.println(F("Extinction"));
      // >>>>>>> ici éteindre  ce que vous voulez <<<<<<<<<<
      systememActif = false; // on mémorise que l'on vient d'éteindre le système
    }
  }

  // ici on peut faire autre chose
  delay(1000); // par exemple attendre une seconde avant de ré-interroger l'horloge 
}

@Hazerty : oui l'ESP 32 parait etre une bonne solution, ca me permettrait de rester sur ma bonne vieille DS1307 et la remettre a l'heure via internet regulierement j'imagine.

ca m'interesse de savoir ce que propose ta serre comme reglages, infos etc...

@J-M-L : j'avoue que je ne comprend pas tout ce que j'ai fais pour la mise en place de l'heure :confused: le morceau de code que tu viens de m'envoyer est particulierement bien detaillé et expliqué, comme RTClib est commune au 1307 et 3132, ca sous entend que si je change de module, j'ai simplement à changer cette ligne la "RTC_DS1307 rtc;" et remettre le module à l'heure ?

en tout cas pour le moment ma bidouille fonctionne, ce matin, arrosage et allumage des lampes sans que je ne fasse rien :D. ca m'as permis de me rendre compte qu'un petit reporting de l'arrosage, taux d'humidité de la terre et dans le futur de la temperature... me serait bien utile pour verifier que tout est ok plus facilement.

Merci à vous pour ces infos, l'aventure continue !

naskaone:
@J-M-L : j'avoue que je ne comprend pas tout ce que j'ai fais pour la mise en place de l'heure :confused: le morceau de code que tu viens de m'envoyer est particulierement bien detaillé et expliqué, comme RTClib est commune au 1307 et 3132, ca sous entend que si je change de module, j'ai simplement à changer cette ligne la "RTC_DS1307 rtc;" et remettre le module à l'heure ?

Tout à fait...