Alors voilà le fichier principal :
// test du 28/02/2023 a 18 H 20
#include <SPI.h>
#include <Ethernet.h>
#include <Wire.h>
#include "AsyncTask.h"
#include "simpleRTC.h"
#define ENABLE_SDCARD false // enable disable SDcard and uncomment library if needed below
#if ENABLE_SDCARD
#include <SdFat.h> // bibliotheque pour carte SD
#endif
/*************************************/
// Pour avoir un mode debug de notre programme
#define DEBUG true // à mettre à false si on ne veut pas de debug
#define DEBUGSTREAM Serial
#if DEBUG
#define DEBUG_PRINT(...) DEBUGSTREAM.print(__VA_ARGS__)
#define DEBUG_PRINTLN(...) DEBUGSTREAM.println(__VA_ARGS__)
#else
#define DEBUG_PRINT(...)
#define DEBUG_PRINTLN(...)
#endif
const bool TEST = 0; // active ou desactive les digitalWrite sur pin
const char* NUMERO_VERSION = "machine etats j-M-L 7.329";
const unsigned long TIMER_A = 7200000UL, TIMER_P = 120000UL, TIMER_V = 30000UL; // 2 heures , 2 minutes et 30 sec.
const unsigned int // pour les heures creuses
HC_START_TIME_N = 1*60 + 30,// 1 H 30 min = 90
HC_END_TIME_N = 7*60 +30, // 7 H 30 min = 450
HC_START_TIME_D = 12*60, // 12 h 00 min = 720
HC_END_TIME_D = 14*60; // 14 h 00 min = 8940
/*************************************/
uint8_t MacAddress[] = {0x90, 0xA2, 0xDA, 0x10, 0x2F, 0x93};
IPAddress ip(192,168,1,111); // L'adresse IP que prendra le shield ethernet
// mettre (0,0,0,0) pour laisser en serveur DHCP sinon ce sera une adresse IP statique .
const unsigned int SERVER_PORT = 80;
EthernetServer webServer(SERVER_PORT);
EthernetUDP Udp;
////* Volets *////
enum t_commandeVolet : uint8_t {FERMER, OUVRIR, ARRETER, FERMER_TOUT, OUVRIR_TOUT, ARRETER_TOUT, NULL_V};
enum t_etatVolet : uint8_t {OUVERT, FERME, EN_FERMETURE, EN_OUVERTURE, ENTROUVERT};
struct t_volet {
uint8_t pinRelaisOuverture; //1
uint8_t pinRelaisFermeture; //2
t_etatVolet etat; //3
const char* nom; //4
uint32_t dureeCourseTotale; //5
uint32_t debutCourse; //6
uint32_t dureeJusquaFinCourse; //7
};
#define tpsDeCourse(hauteur) ((uint32_t) (TIMER_V / 210.0 * (hauteur))) // il faut 30s pour faire 2m10
t_volet lesVolets[] = {
{22, 30, OUVERT, "Cuisine", tpsDeCourse (95), 0, 0},
{23, 31, OUVERT, "Sa manger", tpsDeCourse(210), 0, 0},
{24, 32, OUVERT, "Salon", tpsDeCourse(210), 0, 0},
{25, 33, OUVERT, "Salle TV", tpsDeCourse (95), 0, 0},
{26, 34, OUVERT, "Ch Lucie", tpsDeCourse(103), 0, 0},
{27, 35, OUVERT, "Ch parents", tpsDeCourse(102), 0, 0},
{28, 36, OUVERT, "S D Bains", tpsDeCourse(101), 0, 0},
{29, 37, OUVERT, "Bureau", tpsDeCourse(104), 0, 0}
};
const uint8_t NOMBREDEVOLETS = sizeof(lesVolets) / sizeof(t_volet);
/************************************************************************************/
////* Arrosage *////
bool arrosageAutontialise = false;
bool arrosageAutoON = false;
bool resetZoneArrosee;
uint8_t saison = 5;
enum t_saison : uint8_t {PRINTEMPS, ETE, AUTOMNE, HIVER};
enum t_commandeArrosage : uint8_t {MARCHE, ARRET, MARCHE_TOUT, ARRET_TOUT, TIMERR_A, AUTOMA, NULL_A};
enum t_etat : uint8_t {ACTIF, INACTIF, TIMER, AUTO};
struct t_arrosage { // "Arbres", "Bordures", "Fruitiers", "Haies", "Jardin", "Potager
uint8_t zone; //1 index
const char* nom; //2
uint8_t pinRelais; //3
t_etat etat; //4
uint32_t timerArrosage; //5
uint32_t debutArrosage; //6 utile ?
uint32_t finArrosage; //7 utile ?
// mode auto :
uint8_t joursIntervalle; //8
bool zoneArrosee; //9
uint32_t heureDebutArrosage; //10
uint32_t dureeJusquaFinArrosage; //11
uint32_t timerProchainArrosage; //12
};
float coeffSaison = 1UL;
//#define tempsDArrosage(coeffSaison) ((uint32_t) (TIMER_A * (coeffSaison)))
t_arrosage lesArrosages[] = {
//zone nom pin etat DuréeArrosage coeff // ZA
// 1 2 3 4 5 6 7 8 9 10 11 12
{0, "Arbres", 38, INACTIF, 0, 0, 0, false, 0, 0, TIMER_A, 0},
{1, "Bordures", 39, INACTIF, 0, 0, 0, false, 0, 0, TIMER_A, 0},
{2, "Fruitiers", 40, INACTIF, 0, 0, 0, false, 0, 0, TIMER_A, 0},
{3, "Haies", 41, INACTIF, 0, 0, 0, false, 0, 0, TIMER_A, 0},
{4, "Jardin", 42, INACTIF, 0, 0, 0, false, 0, 0, TIMER_A, 0},
{5, "Potager", 43, INACTIF, 0, 0, 0, false, 0, 0, TIMER_A, 0}
};
const uint8_t NOMBREDARROSAGE = sizeof(lesArrosages) / sizeof(t_arrosage) , HEURE_RESET_A = 24, HEURE_DEBUT_A = 0;
/************************************************************************************/
////* Relais *////
#define RELAIS_ACTIF LOW
#define RELAIS_INACTIF HIGH
enum t_commandeRelais : uint8_t {ACTIVE, INACTIVE, TIMERR_R, NULL_R};
enum t_etatRelais : uint8_t {R_ACTIF, R_INACTIF, R_TIMER};
struct t_relais {
uint8_t pinRelais;
t_etatRelais etat;
const char* nomRelais;
uint32_t timerRelais;
};
t_relais lesRelais[] = {
{44, R_INACTIF, "Portail", TIMER_P},
{45, R_INACTIF, "Heures creuses", 0}
};
const uint8_t NOMBREDERELAIS = sizeof(lesRelais) / sizeof(t_relais);
/************************************************************************************/
////* Commandes web *////
enum : uint8_t {VOLETS_GLOBAL, VOLET_OUVRIR, VOLET_FERMER, VOLET_ARRETER, PORTAIL, ARROSAGE_MARCHE, ARROSAGE_ARRET, ARROSAGE_AUTO, RESTE}; // switch case du parseCommand
struct t_commandeWeb {
bool active;
t_volet* volet; // le pointeur du volet à commander
t_commandeVolet actionCMD_V;
t_arrosage* arrosage;
t_commandeArrosage actionCMD_A;
t_relais* relais;
t_commandeRelais actionCMD_R;
};
t_commandeWeb commandeWeb;
/********************************************************************************************************
Arduino communicates with both the Ethernet Shield and SD card using the SPI bus
This is on digital pins 10, 11, 12, and 13 on the Uno and pins 50, 51, and 52 on the Mega.
Pin 10 is used to select the Ethernet chip and pin 4 for the SD card.
These pins cannot be used for general I/O.
On the Mega, the hardware SS pin, 53, is not used to select either the Ethernet chip or the SD card,
but it must be kept as an output or the SPI interface won't work.
Note that because the Ethernet chip and SD card share the SPI bus, only one at a time can be active.
If you are using both peripherals in your program, this should be taken care of by the corresponding libraries.
If you're not using one of the peripherals in your program, however, you'll need to explicitly deselect it.
To do this with the SD card, set pin 4 as an output and write a high to it.
For the Ethernet chip, set digital pin 10 as a high output.
// ?????????????????????????? i use a mega 2560 , so should i put pin 4, 10, 53 as an output and write a high to it ??????????????
********************************************************************************************************/
/********************************************************************************************************
*** USED PINS communicate with shield and others devices ***
*** 0 , 1 , 2 , 3 , 4 , 10 , 20 , 21 , 50 , 51 , 52 , 53
// 22 => 29 : ouvertures volets
// 30 => 37 fermetures volets
// 38 => 43 arrosages
// 44 = Portail
// 45 = RHC
// 46 ?
// 47 ?
// 48 = alimentation capteur pluie
// 49 = alimentation capteur humidité
// A0 = 54 = capteur pluie
// A1 = 55 = capteur humidité
********************************************************************************************************/
/*** pins definitions ***/
const uint8_t
PLUIE_SENSOR_PIN = A0,
HUMIDITY_SENSOR_PIN = A1,
BROCHE_ONEWIRE = 2,
SDCARD_PIN = 4,
PLUIE_SENSOR_VCC = 48,
HUMIDITY_SENSOR_VCC = 49,
MAX_COMMAND = 30;
AsyncTask<NOMBREDARROSAGE*2 + 5> gestionnaireDeTache;
// autorise un nombre de taches predefinies . 12 pour arrosage et 1 portail + 1 heure + 1 saison .
/*****************************************************************
** This is for our URL Parser. We are expecting an URL in the form
** of http://domain.com/x=v1,y=v2,z=v3
** x, y and z would be the labels of Interests and v1, v2, v3
** will be valued extracted by the parser
******************************************************************/
const char * LABELS_OF_INTEREST[] = {"VG", "VO", "VF","VA", "P", "AM", "AA", "AG","R"}; // envoie requete HTTP
char urlCommand[MAX_COMMAND + 1]; // +1 for the trailing '\0'
const unsigned int MAX_LABELS_OF_INTEREST = sizeof(LABELS_OF_INTEREST) / sizeof(char*);
long VG=0, VO=0, VF=0, VA=0, P=0, AM=0, AA=0, AG=0, R=0;
/************************************************************************************/
////* Capteurs *////
const uint8_t SEUIL_PLUIE = 50, SEUIL_HUMIDITE = 50;
////* NTP UDP */////
char timeServer[] = "ntp.unice.fr";
const unsigned int localPort = 8888, timeOut = 1000; // local port to listen for UDP packets
const uint8_t NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
uint8_t packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
/************************************************************************************/
void setup() {
if (DEBUG) Serial.begin(115200);
Wire.begin();
initWebServer ();
initGestionnaireDeTache ();
for (uint8_t v = 0; v < NOMBREDEVOLETS; v++) initialiserUnVolet(&(lesVolets[v]));
for (uint8_t a = 0; a < NOMBREDARROSAGE; a++) initialiserUnArrosage(&(lesArrosages[a]));
for (uint8_t r = 0; r < NOMBREDERELAIS; r++) initialiserUnRelais(&(lesRelais[r]));
initSDCard ();
initSetupPluie ();
initSetupHumidity ();
if (DEBUG) {
//printServerAddress();
// verif internet acces
if (internetAccessible()) Serial.println (F("setup => acces internet OK"));
else Serial.println(F("setup => Pas d ' acces internet !!!"));
// verif tache en cours au demarrage
/*
uint8_t count = 0;
for (uint8_t i=0; i<255; i++) {
if (gestionnaireDeTache.findAsyncCommand(i)) {
count++;
Serial.print (F("setup => trouver taches au nombre de : "));
Serial.println (i);
}
}
if (! count) Serial.print (F("setup => pas de tache trouvée ."));
*/
/*
for (uint8_t i = 0; i < RELAY_NUMBER; i++) {
Serial.print ("pinRelaisFermeture");
Serial.print (lesVolets[i].pinRelaisFermeture);
Serial.print (" = ") ;
Serial.println (digitalRead(lesVolets[i].pinRelaisFermeture));
Serial.print ("pinRelaisOuverture");
Serial.print (lesVolets[i].pinRelaisOuverture);
Serial.print (" = ") ;
Serial.println (digitalRead(lesVolets[i].pinRelaisOuverture));
Serial.print ("tableau_Etat_Relais");
Serial.print (i);
Serial.println (lesRelais[i].etatRelaisi]);
}*/
}
}
void loop() {
actualiserRTC();
gestionnaireDeTache.updateQueue();
//if (renewDHCPLease())
handleClient(); // we still have a DHCP IP
gererLesVolets();
gererLesArrosages(); // logiquement inutile , en mode manuel en tout cas .
gererLesRelais();
relaisHeureCreuse();
//resetZoneArrosee();
}
le fichier des fonctions de relais :
//// Fonctions de gestion des relais : ////
bool verifPinOK (int8_t pin) { // on s' assure grace a cette fonction que le pin qu ' on recoit est bien un numero valide compris dans la plage de pin que doit gerer notre serveur.
return (pin >= -4 && pin < 53);
}
void initialiserUnRelais (t_relais* unRelais) {
pinMode(unRelais->pinRelais, OUTPUT);
digitalWrite(unRelais->pinRelais, RELAIS_INACTIF); // à l'arret
if (DEBUG) {
Serial.print (F("* initialiserUnRelais => PIN : "));
Serial.println (unRelais->pinRelais);
}
}
void activerUnRelais(t_relais* unRelais) {
if (unRelais->etat != R_ACTIF) {
if (!TEST) digitalWrite(unRelais->pinRelais, RELAIS_ACTIF);
unRelais->etat = R_ACTIF;
}
}
void desactiverUnRelais(t_relais* unRelais) {
if (unRelais->etat != R_INACTIF) {
if (!TEST) digitalWrite(unRelais->pinRelais, RELAIS_INACTIF);
unRelais->etat = R_INACTIF;
}
}
void inverserUnRelais(t_relais* unRelais) {
if (unRelais->etat != R_ACTIF) activerUnRelais(unRelais);
else desactiverUnRelais(unRelais);
}
void inverserUnRelaisEtUnTimer(t_relais* unRelais) {
if (unRelais->etat != R_ACTIF) activerUnRelaisEtUnTimer (unRelais);
else if (unRelais->etat != R_INACTIF) desactiverUnRelaisEtUnTimer (unRelais);
}
void activerUnRelaisEtUnTimer (t_relais* unRelais) {
activerUnRelais(unRelais);
activerUnTimerRelais(unRelais);
}
void desactiverUnRelaisEtUnTimer (t_relais* unRelais) {
desactiverUnRelais(unRelais);
desactiverTimerRelais(unRelais->pinRelais);
}
void gererLesRelais () {
if (commandeWeb.active) {
/*
if (commandeWeb.volet == NULL && commandeWeb.actionCMD_V == NULL_V && commandeWeb.arrosage == NULL && commandeWeb.actionCMD_A == NULL_A && commandeWeb.actionCMD_R == NULL_R) {
commandeWeb.active=false;
if (DEBUG) {
Serial.print (F("* gererLesRelais , 1er if "));
}
}
*/
if (commandeWeb.relais != NULL) for (uint8_t r = 0; r < NOMBREDERELAIS; r++) gererUnRelais(&(lesRelais[r]));
}
//else for (uint8_t r = 0; r < NOMBREDERELAIS; r++) gererUnRelais(&(lesRelais[r]));
}
void gererUnRelais (t_relais* unRelais) {
switch (unRelais->etat) { // R_ACTIF, R_INACTIF, R_TIMER
case R_INACTIF : // actionCMD_R = ACTIVE, INACTIVE, TIMERR_R, NULL_R
if ((commandeWeb.active) && (commandeWeb.relais == unRelais)) {
if (commandeWeb.actionCMD_R == ACTIVE) {
if (DEBUG) {
Serial.print (F("* gererUnRelais => case INACTIF => unRelais->pinRelais : "));
Serial.println (unRelais->pinRelais);
}
activerUnRelais(unRelais);
commandeWeb.active = false;
}
}
break;
case R_ACTIF :
if ((commandeWeb.active) && (commandeWeb.relais == unRelais)) {
if (commandeWeb.actionCMD_R == INACTIVE) {
if (DEBUG) {
Serial.print (F("* gererUnRelais => case ACTIF => unRelais->pinRelais : "));
Serial.println (unRelais->pinRelais);
}
desactiverUnRelais(unRelais);
commandeWeb.active = false;
}
}
break;
case R_TIMER :
if ((commandeWeb.active) && (commandeWeb.relais == unRelais)) {
if (commandeWeb.actionCMD_R == TIMERR_R) {
if (DEBUG) {
Serial.print (F("* gererUnRelais => case TIMERR_R =>unRelais->pinRelais : "));
Serial.println (unRelais->pinRelais);
}
inverserUnRelais(unRelais);
commandeWeb.active = false;
}
}
break;
/*case AUTO :
if ((commandeWeb.active) && (commandeWeb.relais == unRelais)) {
if (commandeWeb.actionCMD_R == AUTO) {
inverserUnRelais(unRelais);
commandeWeb.active = false;
}
}
break;*/
default:
if (DEBUG) Serial.println (F("* gererUnRelais => probleme = case non reconnu !"));
break;
} // fin switch
// comme cette fonction est appellé en permanence , il vaut mieux eviter de mettre quoi que ce soit ici
}
/************************************************************************************/
void relaisHeureCreuse () { // ok
static unsigned long chrono = 0;
unsigned int timestamp = RTC.heure()*60 + RTC.minute();
static int RHC = -1; // jamais lu
static bool oldRHC = false;
if ((RHC == -1) || (millis() - chrono >= TIMER_V)) { // si jamais lue ou lue depuis plus de 30 secondes
if (DEBUG && RHC == -1 ) {
Serial.print (F("relaisHeureCreuse => initialisation sur PIN : "));
Serial.print (lesRelais[1].pinRelais);
Serial.print (F(" , etat : "));
Serial.println (lesRelais[1].etat);
}
// si on est dans le bon crenau horraire
//if ( (timestamp > HC_START_TIME_N && timestamp < HC_END_TIME_N) || (timestamp > HC_START_TIME_D && timestamp < HC_END_TIME_D) ) { // entre 12 et 14 heures + la nuit
if (timestamp > HC_START_TIME_D && timestamp < HC_END_TIME_D ) { // enclenchement uniquement entre 12 et 14 Heures
RHC = 1;
//activerRelais(1);
//if (DEBUG) Serial.println (F("relaisHeureCreuse => etat actif"));
}
else {
RHC = 0;
//desactiverRelais(1);
//if (DEBUG) Serial.println (F("relaisHeureCreuse => etat passif"));
}
if ((oldRHC != RHC) && (RHC != -1)) {
if (DEBUG) {
Serial.print (F("relaisHeureCreuse => oldRHC avant = "));
Serial.print (oldRHC);
Serial.print (F(" , relaisHeureCreuse => RHC = "));
Serial.println (RHC);
}
//inverserRelais(1);
inverserUnRelais(&(lesRelais[1]));
oldRHC = RHC;
}
chrono = millis();
// histoire de verifier le nombre de tache au cours de l' evolution du programme.
/*
if (DEBUG) {
uint8_t count = 0;
for (uint8_t i=0; i<255; i++) {
if (gestionnaireDeTache.findAsyncCommand(i)) {
count++;
Serial.print (F("setup => trouver taches : "));
Serial.println (i);
}
}
if (! count) Serial.print (F("setup => pas de tache trouvée ."));
else {
Serial.print (F("setup => "));
Serial.print (count);
Serial.println (F(" tache(s) trouvée(s) ."));
}
}
*/
}
}
// on recoit le pin du timer asynctask ...
// cette fonction sert uniquement a desactiver le bon relais et mettre a jour l' etat .
// elle est appelée uniquement par le callback du gestionnaire de tache , voir fichier timers_rtc.ino
void desactiverRelais(t_commandID pin) {
for (uint8_t i = 0; i < NOMBREDERELAIS; i++) {
if (lesRelais[i].pinRelais == pin) {
lesRelais[i].etat = R_INACTIF;
if (!TEST) digitalWrite(lesRelais[i].pinRelais, RELAIS_INACTIF);
if (DEBUG) {
Serial.print (F("* desactiverRelais => indice = "));
Serial.print (i);
Serial.print (F(", relais = "));
Serial.println (lesRelais[i].pinRelais);
}
}
}
}
void activerUnTimerRelais (t_relais* unRelais) {
// si une tache existe deja , on la remplace par la nouvelle , donc , 1ere chose , on supprime la tache si elle existe deja .
desactiverTimerRelais(unRelais->pinRelais);
if (!gestionnaireDeTache.findAsyncCommand(unRelais->pinRelais)) {
gestionnaireDeTache.registerAsyncCommand(unRelais->pinRelais, unRelais->timerRelais, desactiverRelais); // normal le reinit ici : oui fonction de callback ( c ' est elle qui reinitialisera le relais a la fin du timer )
if (DEBUG) {
Serial.print (F("* activerTimerRelais => tache "));
Serial.print (unRelais->pinRelais);
Serial.print (F(" enregistrée pour dans "));
Serial.println (unRelais->timerRelais);
}
}
}
void desactiverTimerRelais (uint8_t pin) { // en cas de suppression manuelle du timer
if (gestionnaireDeTache.findAsyncCommand(pin)) {
gestionnaireDeTache.unregisterAsyncCommand(pin);
if (DEBUG) {
Serial.print (F("* desactiverTimerRelais => tache : "));
Serial.print (pin);
Serial.println (F(" supprimee"));
}
}
}
//// FIN Des Fonctions de gestion des relais ////
celui des fonctions serveurs :
//// Fonctions serveur : ////
////* verif acces internet *////
bool attenteChaine(EthernetClient& timeoutClient, const char * endMarker, unsigned long duration) {
int localBufferSize = strlen(endMarker); // we won't need an \0 at the end
char localBuffer[localBufferSize];
int index = 0;
boolean endMarkerFound = false;
unsigned long currentTime;
memset(localBuffer, '\0', localBufferSize); // clear buffer
currentTime = millis();
while (millis() - currentTime <= duration) {
if (timeoutClient.available() > 0) {
if (index == localBufferSize) index = 0;
localBuffer[index] = (uint8_t) timeoutClient.read();
endMarkerFound = true;
for (int i = 0; i < localBufferSize; i++) {
if (localBuffer[(index + 1 + i) % localBufferSize] != endMarker[i]) {
endMarkerFound = false;
break;
}
}
index++;
}
if (endMarkerFound) break;
}
return endMarkerFound;
}
bool internetAccessible() {
const unsigned long timeOut = 1000;
EthernetClient timeoutClient;
boolean r;
// client.connect Returns an int (1,-1,-2,-3,-4) indicating connection status :
// SUCCESS 1
// TIMED_OUT -1
// INVALID_SERVER -2
// TRUNCATED -3
// INVALID_RESPONSE -4
timeoutClient.setTimeout(timeOut);
if (timeoutClient.connect("clients3.google.com", 80) != 1) {
return false;
}
// si on est connnecté on devrait recevoir une réponse HTTP/1.0 204 No Content
timeoutClient.println("GET /generate_204 HTTP/1.0\r\nHost: arduino.cc\r\nUser-Agent: Arduino\r\n");
r = attenteChaine(timeoutClient, "204", timeOut); // on se donne au max timeOut millisecondes pour recevoir la réponse
while(timeoutClient.available()) timeoutClient.read(); // on vide le buffer
timeoutClient.stop();
return r;
}
////* serveur UDP *////
// send an NTP request to the time server at the given address
void sendNTPpacket(char* address) {
memset(packetBuffer, 0, NTP_PACKET_SIZE);
packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clock
packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
// all NTP fields have been given values, now you can send a packet requesting a timestamp:
Udp.beginPacket(address, 123); //NTP requests are to port 123
Udp.write(packetBuffer, NTP_PACKET_SIZE);
Udp.endPacket();
}
////* serveur web *////
void affecteCommandeWeb(bool b, t_volet* v=NULL , t_commandeVolet cv=NULL_V , t_arrosage* a=NULL , t_commandeArrosage ca=NULL_A , t_relais* r=NULL, t_commandeRelais cr=NULL_R) {
commandeWeb.active=b; // bool
commandeWeb.volet=v;
commandeWeb.arrosage=a;
commandeWeb.relais=r;
commandeWeb.actionCMD_V=cv;
commandeWeb.actionCMD_A=ca;
commandeWeb.actionCMD_R=cr;
if (b) {
if (v) gererUnVolet(v);
else if (a) gererUnArrosage(a);
else if (r) gererUnRelais(r);
else if (cv != NULL_V) gererLesVolets();
else if (ca != NULL_A) gererLesArrosages();
else if (cr != NULL_R) gererLesRelais();
}
}
void parseCommand() {
char * item;
boolean labelFound;
long int labelValue = -10;
int labelIndex;
item = strtok(urlCommand, "=");
while (item) {
labelFound = false;
for (unsigned int i = 0; i < MAX_LABELS_OF_INTEREST; ++i) {
if (!strcmp(LABELS_OF_INTEREST[i], item)) {
item = strtok (NULL, ",");
if (item != NULL) {
labelFound = true;
labelIndex = i;
// then parse the value , we expect integers
labelValue = atol(item);
if (DEBUG) {
Serial.print ("labelIndex = ");
Serial.println (labelIndex );
Serial.print ("labelValue = ");
Serial.println (labelValue);
}
} // end if we had a value for the label
} // end string compare
} // end for
// ****************************************************************
// THIS IS WHERE YOU PERFORM YOUR ACTIONS FOR EACH VARIABLE FOUND
// ****************************************************************
if (labelFound && verifPinOK(labelValue)) {
switch (labelIndex) { // VOLETS_GLOBAL, VOLET_OUVRIR, VOLET_FERMER, VOLET_ARRETER, PORTAIL, ARROSAGE, RESTE};
case VOLETS_GLOBAL :// "VG", "VO", "VF","VA", "P", "AG", "AM", "AA", "R"
if(DEBUG) Serial.print(F("* parseCommand => VOLETS_GLOBAL "));
if (labelValue == -2) { // on arrete tous les volets
if(DEBUG) Serial.println(F(" => ARRETER_TOUT"));
//arreterLesVolets();
affecteCommandeWeb(true, NULL, ARRETER_TOUT);
}
else if (labelValue == -3) { // on ouvre tous les volets
if(DEBUG) Serial.println(F(" => OUVRIR_TOUT"));
//ouvrirLesVolets();
affecteCommandeWeb(true, NULL, OUVRIR_TOUT);
}
else if (labelValue == -4) { // on ferme tous les volets
if(DEBUG) Serial.println(F(" => FERMER_TOUT"));
//fermerLesVolets();
affecteCommandeWeb(true, NULL, FERMER_TOUT);
}
break;
case VOLET_OUVRIR :
if(DEBUG) Serial.println(F("* parseCommand => VOLET_OUVRIR"));
affecteCommandeWeb(true, &(lesVolets[labelValue]), OUVRIR);
break;
case VOLET_FERMER :
if(DEBUG) Serial.println(F("* parseCommand => VOLET_FERMER"));
affecteCommandeWeb(true, &(lesVolets[labelValue]), FERMER);
break;
case VOLET_ARRETER :
if(DEBUG) Serial.println(F("* parseCommand => VOLET_ARRETER"));
affecteCommandeWeb(true, &(lesVolets[labelValue]), ARRETER);
break;
case PORTAIL :
if(DEBUG) {
Serial.print(F("* parseCommand => PORTAIL => labelValue = "));
Serial.println(labelValue);
}
//if (! TEST) inverserUnRelaisEtUnTimer (&(lesRelais[0])); // fonctionne aussi
for (uint8_t r = 0; r < NOMBREDERELAIS; r++) {
if (lesRelais[r].pinRelais == labelValue) {
//if (! TEST) inverserUnRelaisEtUnTimer (&(lesRelais[r])); // fonctionne aussi
// Sinon , pour etre uniforme :
affecteCommandeWeb(true, NULL, NULL_V, NULL, NULL_A, &(lesRelais[r]), NULL_R);
// n ' a pas l ' air de vouloir fonctionner sans un enum etat relais specifique
if(DEBUG) {
Serial.print(F("* parseCommand => PORTAIL => envoi = "));
Serial.println(lesRelais[r].pinRelais);
}
}
}
break;
case ARROSAGE_MARCHE : // ARROSAGE_MARCHE, ARROSAGE_ARRET, ARROSAGE
if(DEBUG) Serial.println(F("* parseCommand => ARROSAGE => single => MARCHE"));
affecteCommandeWeb(true, NULL, NULL_V, &(lesArrosages[labelValue]), MARCHE); // passage d ' un int a un pointeur : &(lesArrosages[labelValue])
break;
case ARROSAGE_ARRET :
if(DEBUG) Serial.println(F("* parseCommand => ARROSAGE => single => ARRET"));
affecteCommandeWeb(true, NULL, NULL_V, &(lesArrosages[labelValue]), ARRET);
break;
case ARROSAGE_AUTO :
if (labelValue == -1) {
arrosageAutoON = !arrosageAutoON;
affecteCommandeWeb(true, NULL, NULL_V, NULL, AUTOMA);
if(DEBUG) {
Serial.print(F("* parseCommand => ARROSAGE => AUTO : "));
Serial.println ( arrosageAutoON == false ? F("OFF") : F("ON"));
}
//if (arrosageAutoON == false) // il faut desactiver les arrosages et apeller les bonnes fonctions
}
//else if (labelValue == -2) initArrosageOK = NOMBREDARROSAGE; // reinitialise , on ne l ' appelle pas manuellement ?
else if (labelValue == -3) {
if(DEBUG) Serial.println(F("* parseCommand => ARROSAGE => MARCHE_TOUT"));
affecteCommandeWeb(true, NULL, NULL_V, NULL, MARCHE_TOUT);
}
else if (labelValue == -4) {
if(DEBUG) Serial.println(F("* parseCommand => ARROSAGE => ARRET_TOUT"));
affecteCommandeWeb(true, NULL, NULL_V, NULL, ARRET_TOUT);
}
break;
case RESTE :
break;
default :
if(DEBUG) Serial.println(F("* parseCommand => case INCONNU !!"));
break;
} // fin du switch
} // fin if
else {
item = strtok (NULL, ","); // skip this label value, not recognized
}
item = strtok (NULL, "="); // got to next one - will modify urlCommand
} // fin boucle
}
void handleCommand(EthernetClient& client) {
// the command is in urlCommand
if (strlen(urlCommand) != 0) parseCommand();
sendHTTPResponse(client);
}
void handleClient() {
boolean urlCommandFound = false;
char httpHeader[MAX_COMMAND + 1];
uint8_t httpHeaderIndex = 0;
httpHeader[0] = '\0';
urlCommand[0] = '\0';
EthernetClient client = webServer.available(); // listen for incoming clients
if (client) {
boolean currentLineIsBlank = true;
//if (DEBUG) Serial.println (F("handleClient =>requete HTTP : "));
while (client.connected()) {
if (client.available()) {
char c = client.read();
//if (DEBUG) Serial.print(c); // if you want to see the HTTP request
if (!urlCommandFound) {
httpHeader[httpHeaderIndex++] = c;
httpHeader[httpHeaderIndex] = '\0';
if (httpHeaderIndex > MAX_COMMAND - 1) httpHeaderIndex = MAX_COMMAND - 1;
}
if (c == '\n' && currentLineIsBlank) { // an http request ends with a blank line
handleCommand(client);
delay(10); // give the web browser time to receive the data
client.stop(); // close the connection:
break;
}
if (c == '\n') {
currentLineIsBlank = true; // starting a new line
if (!strncmp("GET / ", httpHeader, 5)) {
strcpy(urlCommand, (httpHeader + 5)); // get rid of the "GET / "
char * firstSpacePtr = strchr(urlCommand, ' ');
if (firstSpacePtr) *firstSpacePtr = '\0'; // get rid of the " HTTP / 1.1 etc
urlCommandFound = true;
}
else {
httpHeaderIndex = 0;
httpHeader[0] = '\0';
}
}
else if (c != '\r') {
currentLineIsBlank = false; // new character on the current line, ignore '\r'
}
} // fin du client.available
} // fin de la boucle while
} // fin du if (client)
}
void printServerAddress() {
if (Ethernet.localIP() != IPAddress(0,0,0,0)) {
Serial.print(F("printServerAddress => Hello , connect to your arduino with http://"));
if (SERVER_PORT != 80) { // 80 is the default port so not needed in the URL
Serial.print(Ethernet.localIP());
Serial.print(F(" : "));
Serial.println(SERVER_PORT);
}
else Serial.println(Ethernet.localIP());
Serial.print (F("printServerAddress => vesrion en cours d ' utilisation : "));
Serial.println (NUMERO_VERSION);
}
else Serial.print(F("printServerAddress => probleme : pas d' addresse IP attribue !"));
}
/* Allows for the renewal of DHCP leases.
// When assigned an IP address via DHCP, ethernet devices are given a lease on the address
// for an amount of time. With Ethernet.maintain(), it is possible to request a renewal from
// the DHCP server. Depending on the server's configuration, you may receive the same address,
// a new one, or none at all.
// best for a server would be to use a static ip, but for demo purpose you are likely to keep your ip long enough */
bool renewDHCPLease() { // uniquement en cas de DHCP activé ,donc pas d' adesse ip statique entree
boolean ok = true;
switch (Ethernet.maintain()) {
case 1:
//renewed fail
if (DEBUG) Serial.println(F("renewDHCPLease => Error: renewed fail"));
ok = false;
break;
case 2:
//renewed success
if (DEBUG) {
Serial.println(F("renewDHCPLease => Renewed success"));
printServerAddress();
}
break;
case 3:
//rebind fail
ok = false;
if (DEBUG) Serial.println(F("renewDHCPLease => Error: rebind fail"));
break;
case 4:
//rebind success
if (DEBUG) {
Serial.println(F("renewDHCPLease => Rebind success"));
//printServerAddress();
}
break;
default:
//nothing happened
break;
}
return ok;
}
//// FIN Des Fonctions serveur ////
celui qui affiche la page web :
//// Fonctions de la page WEB : ////
void sendHTTPResponse(EthernetClient& client) {
//infos pour le navigateur
client.println (F("HTTP/1.1 200 OK")); // type du HTML
client.println (F("Content-Type: text/html; charset=UTF8")); //type de fichier et encodage des caractères
client.println (F("Connection: close")); // fermeture de la connexion quand toute la réponse sera envoyée
client.println();
//balises d'entête
client.println (F("<!DOCTYPE HTML>"));
//client.print(F("<html><head><meta http-equiv='Refresh' content='31'; URL='http://"));
//client.print (ip);
//client.print(F("/'>"));
client.print (F("<html><head>"));
client.print (F("<style>body {text-align:center;}</style></head>"));
client.println (F("<body bgcolor='#00979C'>")); // page backgroud color
//client.println (F("<body bgcolor='#41B3A4'>")); // page backgroud color
//**********************************************************//
corpsPage(client); // fonction pour le corps
//**********************************************************//
client.println(F("</body></html>"));// fin de page
/*
if (DEBUG) {
// affichage des etats des relais lors d ' une action sur le serveur web
for (uint8_t i = 0; i < RELAY_NUMBER; i++) {
Serial.print (F("sendHTTPResponse => Relais numero : "));
Serial.print (i);
Serial.print (F(" etat = "));
Serial.println (lesRelais[i].etat);
}
// affichage des taches asynchrones en cours lors d ' une action sur le serveur web
uint8_t count = 0;
for (uint8_t i=0; i<255; i++) {
if (gestionnaireDeTache.findAsyncCommand(i)) {
count++;
Serial.print (F("* sendHTTPResponse => find tache : "));
Serial.println (i);
}
}
if (! count) Serial.print (F("pas de tache trouvée ."));
}
*/
}
void corpsPage (EthernetClient& client) {
welcomeCorps (client);
ephemerideCorps (client);
voletsCorps (client);
arrosageCorps (client);
//BALCorps (client);
relaisAutreCorps (client);
}
//// FIN Des Fonctions de la page WEB ////
//// Fonctions du corps de la page WEB ////
void welcomeCorps (EthernetClient& client) { // Print Welcome IP ADRESS :
if (Ethernet.localIP() != IPAddress(0,0,0,0)) {
client.print(F("Bienvenue , l ' adresse IP de votre arduino est : "));
if (SERVER_PORT != 80) { // 80 is the default port so not needed in the URL
client.print(Ethernet.localIP());
client.print(F(" : "));
client.println(SERVER_PORT);
}
else client.print(Ethernet.localIP());
}
client.print (F(" , vesrion en cours d ' utilisation : "));
client.println (NUMERO_VERSION);
client.println (F("</br></br>"));
if (DEBUG) {
if (ENABLE_SDCARD) {
client.print (F("welcomeCorps => La carte SD est activee sur le SDCARD_PIN : "));
client.println (SDCARD_PIN);
client.println (F("</br>"));
}
}
}
void ephemerideCorps (EthernetClient& client) { // Print Welcome time ephemeride
affichageDateHeure (client);
client.print (readPluieSensor() == true ? F(" il pleut ! ") : F(" il ne pleut pas . "));
client.print (F("Le sol est "));
client.print (readHumiditySensor() == true ? F("sec .") : F("humide ."));
client.println (F("</br></br>"));
// Actualise button
client.print (F("<a><button onclick=\"location.href='Z'\" type='button'>Actualiser</button></a>"));
client.println (F("</br></br>"));
if (DEBUG && TEST) client.println (F("MODE TEST ET DEBUG ACTIFS !!!"));
else if (DEBUG) client.println (F("MODE DEBUG ACTIF !!!"));
else if (TEST) client.println (F("MODE TEST ACTIF !!!"));
}
void voletsCorps (EthernetClient& client) { // Relais volets
client.print (F("<TABLE width=90% border=1 align='center'><TR><TD colspan="));
client.print (NOMBREDEVOLETS);
client.println (F("><b>VOLETS ROULANTS</b></TD></TR>")); // en tete du tableau
{ // debut de la 1ere ligne du tableau : // affichage des noms seulements
client.println (F("<TR>"));
for (uint8_t i=0; i<NOMBREDEVOLETS; i++) {
client.print (F("<TD width=10%>"));
client.print (lesVolets[i].nom);
client.println (F("</TD>"));
} // fin de boucle
client.println (F("</TR>"));
} // fin de la 1ere ligne du tableau
{ // debut de la 2eme ligne du tableau : boutons ouvertures
client.println (F("<TR>"));
//t_etatVolet : uint8_t { OUVERT, FERME, EN_FERMETURE, EN_OUVERTURE, ENTROUVERT};
for (uint8_t i=0; i<NOMBREDEVOLETS; i++) { // ligne ouverture des relais
if (lesVolets[i].etat == EN_OUVERTURE) {
client.print (F("<TD width=10%><a><button onclick=\"location.href='VA="));
client.print (i);
client.println (F("'\" type='button'> Stop</button></a></TD>"));
}
else if (lesVolets[i].etat == OUVERT) client.println (F("<TD width=10%></TD>"));
else {
client.print (F("<TD width=10%><a><button onclick=\"location.href='VO="));
client.print (i);
client.println (F("'\" type='button'>Ouvrir</button></a></TD>"));
}
} // fin de boucle
client.println (F("</TR>"));
} // fin de la 2eme ligne du tableau
{ // debut de la 3eme ligne du tableau : boutons fermers
client.println (F("<TR>")); // boutons fermeture volets
for (uint8_t i=0; i<NOMBREDEVOLETS; i++) {
if (lesVolets[i].etat == EN_FERMETURE) {
client.print (F("<TD width=10%><a><button onclick=\"location.href='VA="));
client.print (i);
client.println (F("'\" type='button'> Stop</button></a></TD>"));
}
else if (lesVolets[i].etat == FERME) client.println (F("<TD width=10%></TD>"));
else {
client.print (F("<TD width=10%><a><button onclick=\"location.href='VF="));
client.print (i);
client.println (F("'\" type='button'>Fermer</button></a></TD>"));
}
} // fin de boucle
client.println (F("</TR>"));
} // fin de la 3eme ligne du tableau
{ // debut de la 4eme ligne du tableau : boutons groupes
client.println (F("<TR>"));
// bouton tout ouvrir
client.println (F("<TD width=10%><a><button onclick=\"location.href='VG=-3'\" type='button'>Ouvrir</br>les volets</button></a></TD>"));
// bouton tout stopper
client.println (F("<TD width=10%><a><button onclick=\"location.href='VG=-2'\" type='button'>Stopper</br>les volets</button></a></TD>"));
// bouton tout fermer
client.println (F("<TD width=10%><a><button onclick=\"location.href='VG=-4'\" type='button'>Fermer</br>les volets</button></a></TD>"));
// case vide
client.println (F("<TD width=10%></TD>"));
// bouton ouvrir groupe jour
client.println (F("<TD width=10%><a><button onclick=\"location.href='VO=0,VO=1,VO=2,VO=3'\" type='button'>Ouvrir groupe jour</button></a></TD>"));
// bouton ouvrir groupe nuit
client.println (F("<TD width=10%><a><button onclick=\"location.href='VO=4,VO=5,VO=6,VO=7'\" type='button'>Ouvrir groupe nuit</button></a></TD>"));
// bouton fermer groupe jour
client.println (F("<TD width=10%><a><button onclick=\"location.href='VF=0,VF=1,VF=2,VF=3'\" type='button'>Fermer groupe jour</button></a></TD>"));
// bouton fermer groupe nuit
client.println (F("<TD width=10%><a><button onclick=\"location.href='VF=4,VF=5,VF=6,VF=7'\" type='button'>Fermer groupe nuit</button></a></TD>"));
client.println (F("</TR>"));
} // fin de la 4eme ligne du tableau
client.println(F("</TABLE>"));
} // fin du tableau volets
void arrosageCorps (EthernetClient& client) {
{ // en tete du tableau
client.println (F("</br>"));
client.print (F("<TABLE width=90% border=1 align='center'><TR><TD colspan="));
client.print (NOMBREDARROSAGE + 4); // +4 pour arrosage mode global et mode auto
client.print (F("><b>ARROSAGE</b>"));
client.println (F("</TD></TR>")); // en tete du tableau
}
{ // debut de la 1ere ligne du tableau : affichage des noms seulement
client.print (F("<TR>"));
for (uint8_t i=0; i < NOMBREDARROSAGE; i++) {
client.print (F("<TD width=10%>"));
client.print (lesArrosages[i].nom);
client.println (F("</TD>"));
} // fin de boucle
client.println (F("<TD colspan=4 width=30%>Global</TD>"));
client.println (F("</TR>"));
} // fin de la 1ere ligne du tableau
{ // debut de la 2eme ligne du tableau : boutons
client.println (F("<TR>"));
for (uint8_t i = 0; i < NOMBREDARROSAGE; i++) { // ligne ouverture des relais
client.print (lesArrosages[i].etat == INACTIF ? F("<TD width=10%><a><button onclick=\"location.href='AM=") : F("<TD width=10%><a><button onclick=\"location.href='AA="));
client.print (i);
client.print (F("'\" type='button'>"));
client.print (lesArrosages[i].etat == INACTIF ? F("OFF") : F("ON"));
client.println (F("</button></a></TD>"));// fin du lien
} // fin de boucle
client.println (F("<TD width=10%><a><button onclick=\"location.href='AG=-3'\" type='button'>Marche</button></a></TD>")); // MARCHE_TOUT
client.println (F("<TD width=10%><a><button onclick=\"location.href='AG=-4'\" type='button'>Arret</button></a></TD>")); // ARRET_TOUT
client.println (F("<TD width=10%><a><button onclick=\"location.href='AG=-2'\" type='button'>Mode Auto</button></a></TD>")); // initArrosageOK = NOMBREDARROSAGE;
client.print (F("<TD width=10%><a><button onclick=\"location.href='AG=-1'\" type='button'>")); // arrosageAutoON = !arrosageAutoON;
client.println (arrosageAutoON == true ? F("Auto ON </button></a></TD>") : F("Auto OFF </button></a></TD>"));// fin du lien
client.println (F("</TR>"));
} // fin de la 2eme ligne du tableau
client.println (F("</TABLE>"));
}
/*void BALCorps (EthernetClient& client) {
}*/
void relaisAutreCorps (EthernetClient& client) {
{ // en tete du tableau
client.println (F("</br>"));
client.print (F("<TABLE width=90% border=1 align='center'><TR><TD colspan="));
client.print (NOMBREDERELAIS);
client.print (F("><b>RELAIS AUTRE</b>"));
client.println (F("</TD></TR>"));
} // fin en tete du tableau
{ // debut de la 1ere ligne du tableau : // affichage des noms seulements
client.println (F("<TR>"));
for (uint8_t i = 0; i < NOMBREDERELAIS; i++) {
client.print (F("<TD width=10%>"));
client.print (lesRelais[i].nomRelais);
client.println (F("</TD>"));
} // fin de boucle
client.println (F("</TR>"));
} // fin de la 1ere ligne du tableau.
{ // debut de la 2eme ligne du tableau :
client.println (F("<TR>"));
for (uint8_t i = 0; i < NOMBREDERELAIS; ++i) {
if (strcmp(lesRelais[i].nomRelais, "Portail") == 0) {
client.print (F("<TD width=10%><a><button onclick=\"location.href='P="));
client.print (lesRelais[i].pinRelais);
client.print (F("'\" type='button'>"));
client.print (lesRelais[i].etat == RELAIS_INACTIF ? F("Ouvrir") : F("Fermer"));
client.println (F("</button></a></TD>"));// fin du lien
}
if (strcmp(lesRelais[i].nomRelais, "Heures creuses") == 0) {
client.print (F("<TD width=10%>"));
client.print (lesRelais[i].etat == RELAIS_INACTIF ? F("Desactivé") : F("Activé"));
client.println (F("</TD>"));// Pas de lien
}
} // fin de boucle
client.println (F("</TR>"));
} // fin de la 2eme ligne du tableau
client.println (F("</TABLE>"));
}
//// FIN Des Fonctions du corps de la page WEB ////
//// Fonctions speciales affichage de la page WEB ////
const char* afficherJourSemaine(uint8_t joursem) {
const char* jours[] {"Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"};
return jours[joursem]; // de 0 à 6
}
void print2Digits(EthernetClient& client, uint8_t nombre) {
if (aficher0ouPas(nombre)) client.write('0');
client.print (nombre);
}
inline bool aficher0ouPas(uint8_t nombre) {return (nombre < 10);} // vrai si plus petit que 10
// inline Comme la fonction est courte c'est pour dire au compilateur qu'il peut "copier coller ce code" à la place d'appeler la fonction s'il pense que ça sera plus rapide / simple / efficace. bien sûr ça rallonge le code mais on gagne un appel de fonction.
void affichageDateHeure (EthernetClient& client) {
client.print (F("Aujourd ' hui nous sommes le "));
client.print (afficherJourSemaine(RTC.jourSemaine()));
client.print (F(" "));
print2Digits(client, RTC.jour());
client.print (F(" / "));
print2Digits(client, RTC.mois());
client.print (F(" / "));
client.print (F("20"));
client.print (RTC.annee());
client.print (F(" , il est : "));
client.print (RTC.heure());
client.print (F(" H "));
client.print (RTC.minute());
client.print (F(" min "));
client.print (RTC.seconde());
client.print (F(" sec ."));
}
Voilà , normalement pour ce qui est des relais il ne devrait rien manquer .
la fonction commandeWeb est situé dans le fichier des fonctions serveur .
je rajoute les autres fichiers pour completer le code , mais ca ne devrait pas etre necessaire de les voir pour trouver le bug , cela dit ils peuvent aider a comprendre le fonctionnement au cas ou :
void initialiserUnVolet(t_volet* unVolet) {
pinMode(unVolet->pinRelaisOuverture, OUTPUT);
digitalWrite(unVolet->pinRelaisOuverture, RELAIS_INACTIF); // à l'arret
if (DEBUG) {
Serial.print (F("* initialiserUnVolet => PIN ouverture : "));
Serial.println (unVolet->pinRelaisOuverture);
}
pinMode(unVolet->pinRelaisFermeture, OUTPUT);
digitalWrite(unVolet->pinRelaisFermeture, RELAIS_INACTIF); // à l'arret
if (DEBUG) {
Serial.print (F("* initialiserUnVolet => PIN fermeture : "));
Serial.println (unVolet->pinRelaisFermeture);
}
}
void ouvrirUnVolet(t_volet* unVolet) {
if (unVolet->etat != OUVERT) {
if (!TEST) digitalWrite(unVolet->pinRelaisOuverture, RELAIS_ACTIF);
unVolet->debutCourse = millis();
unVolet->etat = EN_OUVERTURE;
}
}
void fermerUnVolet(t_volet* unVolet) {
if (unVolet->etat != FERME) {
if (!TEST) digitalWrite(unVolet->pinRelaisFermeture, RELAIS_ACTIF);
unVolet->debutCourse = millis();
unVolet->etat = EN_FERMETURE;
}
}
void arreterUnVolet(t_volet* unVolet) {
if (!TEST) digitalWrite(unVolet->pinRelaisOuverture, RELAIS_INACTIF);
if (!TEST) digitalWrite(unVolet->pinRelaisFermeture, RELAIS_INACTIF);
unVolet->etat = ENTROUVERT; // par défaut on ne sait pas s'il est en haut ou en bas
if(DEBUG) {
if (unVolet->etat == EN_FERMETURE) {
Serial.print(F("EN_FERMETURE : "));
Serial.println(millis());
}
else if (unVolet->etat == EN_OUVERTURE) {
Serial.print(F("EN_OUVERTURE : "));
Serial.println(millis());
}
}
}
void gererUnVolet(t_volet* unVolet) {
switch (unVolet->etat) { // OUVERT, FERME, EN_FERMETURE, EN_OUVERTURE, ENTROUVERT
case OUVERT: // on regarde si on a un ordre en attente et s'il est pour nous
if ((commandeWeb.active) && (commandeWeb.volet == unVolet)) { // la seule commande à accepter c'est de fermer
if (commandeWeb.actionCMD_V == FERMER) fermerUnVolet(unVolet);
commandeWeb.active = false;
}
break;
case FERME: // on regarde si on a un ordre en attente et s'il est pour nous
if ((commandeWeb.active) && (commandeWeb.volet == unVolet)) { // la seule commande à accepter c'est d'ouvrir
if (commandeWeb.actionCMD_V == OUVRIR) ouvrirUnVolet(unVolet);
commandeWeb.active = false;
}
break;
case EN_FERMETURE:
if (millis() - unVolet->debutCourse >= (unVolet->dureeCourseTotale - unVolet->dureeJusquaFinCourse)) { // on regarde si le temps est écoulé , arrive en fin de course
arreterUnVolet(unVolet);
unVolet->dureeJusquaFinCourse = unVolet->dureeCourseTotale;
unVolet->etat = FERME;
}
else { // cas du stop ou d ' inversion de sens
if ((commandeWeb.active) && (commandeWeb.volet == unVolet)) { // on regarde si on a un ordre en attente et s'il est pour nous
if (commandeWeb.actionCMD_V == OUVRIR) { // on repart en sens inverse , donc on met à jour le temps restant pour ouverture complète , cas de l ' inversion de sens
arreterUnVolet(unVolet);
unVolet->dureeJusquaFinCourse += (millis() - unVolet->debutCourse);
delay(100);
ouvrirUnVolet(unVolet);
}
else if (commandeWeb.actionCMD_V == ARRETER) { // on met à jour le temps restant pour ouverture complète , cas du STOP
unVolet->dureeJusquaFinCourse += (millis() - unVolet->debutCourse);
arreterUnVolet(unVolet);
}
commandeWeb.active = false;
}
}
/*if(DEBUG) {
Serial.print(F("unVolet->dureeCourseTotale = "));
Serial.println(unVolet->dureeCourseTotale);
Serial.print(F("unVolet->dureeJusquaFinCourse = "));
Serial.println(unVolet->dureeJusquaFinCourse);
Serial.print(F("unVolet->debutCourse = "));
Serial.println(unVolet->debutCourse);
}*/
break;
case EN_OUVERTURE:
if (millis() - unVolet->debutCourse >= unVolet->dureeJusquaFinCourse) { // on regarde si le temps écoulé est supérieur au temps restant pour ouverture , arrive en fin de course
arreterUnVolet(unVolet);
unVolet->dureeJusquaFinCourse = 0;
unVolet->etat = OUVERT;
}
else { // cas du stop ou d ' inversion de sens
if ((commandeWeb.active) && (commandeWeb.volet == unVolet)) { // on regarde si on a un ordre en attente et s'il est pour nous
if (commandeWeb.actionCMD_V == FERMER) { // on repart en sens inverse , donc on met à jour le temps restant pour ouverture complète , cas de l ' inversion de sens
arreterUnVolet(unVolet);
unVolet->dureeJusquaFinCourse -= (millis() - unVolet->debutCourse);
delay(100);
fermerUnVolet(unVolet);
}
else if (commandeWeb.actionCMD_V == ARRETER) { // on met à jour le temps restant pour ouverture complète
unVolet->dureeJusquaFinCourse -= (millis() - unVolet->debutCourse);
arreterUnVolet(unVolet);
}
commandeWeb.active = false;
}
}
/*if(DEBUG) {
Serial.print(F("unVolet->dureeCourseTotale = "));
Serial.println(unVolet->dureeCourseTotale);
Serial.print(F("unVolet->dureeJusquaFinCourse = "));
Serial.println(unVolet->dureeJusquaFinCourse);
Serial.print(F("unVolet->debutCourse = "));
Serial.println(unVolet->debutCourse);
}*/
break;
case ENTROUVERT:
if ((commandeWeb.active) && (commandeWeb.volet == unVolet)) { // on regarde si on a un ordre en attente et s'il est pour nous
if (commandeWeb.actionCMD_V == OUVRIR) ouvrirUnVolet(unVolet);
else if (commandeWeb.actionCMD_V == FERMER) fermerUnVolet(unVolet);
commandeWeb.active = false;
}
break;
default :
if(DEBUG) {
Serial.print(F("commandeWeb.active apres = "));
Serial.println(commandeWeb.active);
Serial.print(F("commandeWeb.actionCMD_V apres = "));
Serial.println(commandeWeb.actionCMD_V);
}
commandeWeb.active = false;
break;
} // fin du switch
// comme cette fonction est appellé en permanence , il vaut mieux eviter de mettre quoi que ce soit ici
} //fin fonction
void gererLesVolets() {
if (commandeWeb.active && commandeWeb.volet == NULL && commandeWeb.arrosage == NULL && commandeWeb.actionCMD_A == NULL_A) {
if(commandeWeb.actionCMD_V == FERMER_TOUT) for (uint8_t v = 0; v < NOMBREDEVOLETS; v++) fermerUnVolet(&(lesVolets[v]));
else if (commandeWeb.actionCMD_V == OUVRIR_TOUT) for (uint8_t v = 0; v < NOMBREDEVOLETS; v++) ouvrirUnVolet(&(lesVolets[v]));
else if (commandeWeb.actionCMD_V == ARRETER_TOUT) for (uint8_t v = 0; v < NOMBREDEVOLETS; v++) arreterUnVolet(&(lesVolets[v]));
commandeWeb.active=false;
}
else for (uint8_t v = 0; v < NOMBREDEVOLETS; v++) gererUnVolet(&(lesVolets[v]));
}
//// Fonctions d ' arrosage : ////
void initialiserUnArrosage(t_arrosage* unArrosage) {
pinMode(unArrosage->pinRelais, OUTPUT);
digitalWrite(unArrosage->pinRelais, RELAIS_INACTIF); // à l'arret
if (DEBUG) {
Serial.print (F("* initialiserUnArrosage => PIN : "));
Serial.println (unArrosage->pinRelais);
}
}
//// mode manuel ////
void activerTimerArrosage (t_arrosage* unArrosage) {
// si une tache existe deja , on la remplace par la nouvelle , donc , 1ere chose , on supprime la tache si elle existe deja .
desactiverTimerArrosage(unArrosage->pinRelais);
if (!gestionnaireDeTache.findAsyncCommand(unArrosage->pinRelais)) {
gestionnaireDeTache.registerAsyncCommand(unArrosage->pinRelais, unArrosage->timerArrosage, desactiverArrosage);// normal le reinit ici : oui fonction de callback ( c ' est elle qui reinitialisera le relais a la fin du timer )
if (DEBUG) {
Serial.print (F("* activerTimerArrosage => tache "));
Serial.print (unArrosage->pinRelais);
Serial.print (F(" enregistrée pour dans "));
Serial.println (unArrosage->timerArrosage);
}
}
}
// pour supprimer le timer lors de l' arret manuel d ' un arrosage si celui-ci a été activé
void desactiverTimerArrosage (uint8_t pin) {
if (gestionnaireDeTache.findAsyncCommand(pin)) {
gestionnaireDeTache.unregisterAsyncCommand(pin);
if (DEBUG) {
Serial.print (F("* desactiverTimerArrosage => tache : "));
Serial.print (pin);
Serial.println (F(" supprimee"));
}
}
else { // gestion des doubles ID manuel / auto
pin=pin+100;
if (gestionnaireDeTache.findAsyncCommand(pin)) {
gestionnaireDeTache.unregisterAsyncCommand(pin);
if (DEBUG) {
Serial.print (F("* desactiverTimerArrosage => tache : "));
Serial.print (pin);
Serial.println (F(" supprimee"));
}
}
}
}
// on recoit le pin du timer asynctask ...
// cette fonction sert uniquement a desactiver le bon relais et mettre a jour l' etat .
// elle est appelée uniquement par le callback du gestionnaire de tache , voir fichier timers_rtc.ino
void desactiverArrosage(t_commandID pin) {
for (uint8_t i = 0; i < NOMBREDARROSAGE; i++) {
if (lesArrosages[i].pinRelais == pin) {
lesArrosages[i].etat = INACTIF;
if (!TEST) digitalWrite(lesArrosages[i].pinRelais, RELAIS_INACTIF);
lesArrosages[i].finArrosage = millis();
if (DEBUG) {
Serial.print (F("* desactiverArrosage => indice = "));
Serial.print (i);
Serial.print (F(", relais = "));
Serial.println (lesArrosages[i].pinRelais);
}
}
}
}
void activerUnArrosageEtUnTimer(t_arrosage* unArrosage) {
if (!TEST) digitalWrite(unArrosage->pinRelais, RELAIS_ACTIF);
unArrosage->etat = ACTIF;
//activerTimerArrosage (unArrosage->zone);
activerTimerArrosage (unArrosage);
unArrosage->debutArrosage = millis(); // voir comment faire pour afficher le temps d' arrosage effectue pour chaque zone active.
unArrosage->finArrosage = 0;
if (DEBUG) {
Serial.print (F("* activerUnArrosageEtUnTimer => "));
Serial.print (F("unArrosage->zone : "));
Serial.print (unArrosage->zone);
Serial.print (F(", unArrosage->pinRelais : "));
Serial.println (unArrosage->pinRelais);
}
}
void desactiverUnArrosageEtUnTimer(t_arrosage* unArrosage) {
if (DEBUG) {
Serial.print (F("* desactiverUnArrosageEtUnTimer => "));
Serial.print (F("unArrosage->zone : "));
Serial.print (unArrosage->zone);
Serial.print (F(", unArrosage->pinRelais : "));
Serial.println (unArrosage->pinRelais);
}
if (!TEST) digitalWrite(unArrosage->pinRelais, RELAIS_INACTIF);
unArrosage->etat = INACTIF;
desactiverTimerArrosage (unArrosage->pinRelais);
//unArrosage->debutArrosage = millis(); // voir comment faire pour afficher le temps d' arrosage effectue pour chaque zone active.
unArrosage->finArrosage = millis();
}
void inverserUnArrosageEtUnTimer(t_arrosage* unArrosage) {
if (unArrosage->etat != ACTIF) activerUnArrosageEtUnTimer (unArrosage);
else if (unArrosage->etat != INACTIF) desactiverUnArrosageEtUnTimer (unArrosage);
}
void activerUnArrosage(t_arrosage* unArrosage) {
if (!TEST) digitalWrite(unArrosage->pinRelais, RELAIS_ACTIF);
unArrosage->debutArrosage = millis(); // voir comment faire pour afficher le temps d' arrosage effectue pour chaque zone active.
unArrosage->finArrosage = 0;
unArrosage->etat = ACTIF;
if (DEBUG) {
Serial.print (F("* activerUnArrosage : "));
Serial.println (unArrosage->pinRelais);
}
}
void desactiverUnArrosage(t_arrosage* unArrosage) {
unArrosage->finArrosage = millis();
if (!TEST) digitalWrite(unArrosage->pinRelais, RELAIS_INACTIF);
unArrosage->etat = INACTIF;
if (DEBUG) {
Serial.print (F("* desactiveArrosage : "));
Serial.println (unArrosage->pinRelais);
}
}
void gererUnArrosage(t_arrosage* unArrosage) {
switch (unArrosage->etat) { // ACTIF, INACTIF, TIMER, AUTO
case INACTIF : // MARCHE, ARRET, NULL_A, MARCHE_TOUT, ARRET_TOUT
if ((commandeWeb.active) && (commandeWeb.arrosage == unArrosage)) {
if (commandeWeb.actionCMD_A == MARCHE) {
if (DEBUG) {
Serial.print (F("* gererUnArrosage => case inactif => unArrosage-> zone : "));
Serial.print (unArrosage->zone);
Serial.print (F(", unArrosage->pinRelais : "));
Serial.println (unArrosage->pinRelais);
}
activerUnArrosageEtUnTimer (unArrosage);
commandeWeb.active = false;
}
}
break;
case ACTIF :
if ((commandeWeb.active) && (commandeWeb.arrosage == unArrosage)) {
if (commandeWeb.actionCMD_A == ARRET) {
if (DEBUG) {
Serial.print (F("* gererUnArrosage => case actif => unArrosage-> zone : "));
Serial.print (unArrosage->zone);
Serial.print (F(", unArrosage->pinRelais : "));
Serial.println (unArrosage->pinRelais);
}
desactiverUnArrosageEtUnTimer(unArrosage);
commandeWeb.active = false;
}
}
break;
case TIMER :
if ((commandeWeb.active) && (commandeWeb.arrosage == unArrosage)) {
if (commandeWeb.actionCMD_A == TIMERR_A) {
inverserUnArrosageEtUnTimer(unArrosage);
commandeWeb.active = false;
if (DEBUG) {
Serial.print (F("* gererUnArrosage => case TIMER => unArrosage-> zone : "));
Serial.print (unArrosage->zone);
Serial.print (F(", unArrosage->pinRelais : "));
Serial.println (unArrosage->pinRelais);
}
}
}
break;
case AUTO :
if ((commandeWeb.active) && (commandeWeb.arrosage == unArrosage)) {
if (commandeWeb.actionCMD_A == AUTOMA) {
if (DEBUG) {
Serial.print (F("* gererUnArrosage => case AUTOMA => unArrosage-> zone : "));
Serial.print (unArrosage->zone);
Serial.print (F(", unArrosage->pinRelais : "));
Serial.println (unArrosage->pinRelais);
}
inverserUnArrosageEtUnTimer(unArrosage);
commandeWeb.active = false;
}
} break;
default:
if (DEBUG) Serial.println (F("* gererUnArrosage => probleme = case non reconnu !"));
break;
} // fin switch
// comme cette fonction est appellé en permanence , il vaut mieux eviter de mettre quoi que ce soit ici
}
void gererLesArrosages() {
if (commandeWeb.active && commandeWeb.arrosage == NULL && commandeWeb.volet == NULL && commandeWeb.actionCMD_V == NULL_V) {
if(commandeWeb.actionCMD_A == MARCHE_TOUT) for (uint8_t a = 0; a < NOMBREDARROSAGE; a++) activerUnArrosage(&(lesArrosages[a]));
else if(commandeWeb.actionCMD_A == ARRET_TOUT) for (uint8_t a = 0; a < NOMBREDARROSAGE; a++) desactiverUnArrosage(&(lesArrosages[a]));
else if (commandeWeb.actionCMD_A == AUTOMA) {
if (arrosageAutoON) for (uint8_t a = 0; a < NOMBREDARROSAGE; a++) initialArrosageAuto(&(lesArrosages[a]));
else for (uint8_t a = 0; a < NOMBREDARROSAGE; a++) desactiverUnArrosageEtUnTimer(&(lesArrosages[a]));
}
commandeWeb.active=false;
}
else for (uint8_t a = 0; a < NOMBREDARROSAGE; a++) gererUnArrosage(&(lesArrosages[a]));
}
/* mode manuel */
/***************************************************************************************************************/
/* mode auto */
void initialArrosageAuto (t_arrosage* unArrosage) {
static uint8_t initialAutoA = NOMBREDARROSAGE;
// objectif lancer les taches auto a intervalles reguliers
// et remplir la structure et tableau arrosage avec les valeurs pour travailler
if (arrosageAutoON && initialAutoA) {
// si on desire se fier au relais utilisé , il faut d' abord recuperer celui-ci : lesArrosages[i].pinRelais
uint8_t ID100 = unArrosage->pinRelais + 100;
calculDataArrosageAuto(unArrosage);
gestionnaireDeTache.registerAsyncCommand(ID100, TIMER_V, marcheArrosageAuto); // initialisation autonome : ID 100 a 105
// on active une nouvelle tache ayant pour id le numero de pin + 100 / un temps de 30 secondes / et la fonction automatique d ' arrosage pour callback .
// NOTE : on n ' active pas les relais ici , il s' agist juste de lancer la tache apres l' intervalle defini .
if (DEBUG) {
Serial.print (F("* initialArrosageAuto => effectue sur zone : "));
Serial.print (unArrosage->zone);
Serial.print (F(". tache d ' arrosage principale enclenchée dans "));
Serial.print (TIMER_V);
Serial.print (F(". ID100 : "));
Serial.print (ID100);
Serial.print (F(" sur pin correspondant : "));
Serial.print (unArrosage->pinRelais);
Serial.print (F(", unArrosage->joursIntervalle : "));
Serial.print (unArrosage->joursIntervalle);
Serial.print (F(", unArrosage->timerProchainArrosage : "));
Serial.println (unArrosage->timerProchainArrosage);
}
initialAutoA--;
}
}
void marcheArrosageAuto (t_commandID ID100) { // ID100 est le numero de pin +100 , pas un index du tableau
uint8_t pin = ID100-100;
for (uint8_t a = 0; a < NOMBREDARROSAGE; a++) {
if (lesArrosages[a].pinRelais == pin ) {
lesArrosages[a].zoneArrosee = false;
//if (saison != HIVER && !lesArrosages[pin].zoneArrosee) {
//if (!lesArrosages[pin].zoneArrosee) { // la condition peut si zone arrosée vaut vrai , bloquer la creation de la tache d' arrosage
lesArrosages[a].etat = ACTIF; // gestion etat du relais
if (!TEST) digitalWrite (lesArrosages[a].pinRelais , RELAIS_ACTIF); // gestion du relais
gestionnaireDeTache.registerAsyncCommand(ID100, lesArrosages[a].dureeJusquaFinArrosage, resetTimerArrosageAuto);
// on utilise ID100 pour les taches automatiques / la durée de l' arrosage desirée / la fonction qui arretera le relais ( et l' arrosage donc ) et qui lancera le prochain arrosage a l 'heure desirée .
if (DEBUG) {
Serial.print (F("* marcheArrosageAuto => tache arrosageAuto id100 : "));
Serial.print (ID100);
Serial.print (F(" lance pendant "));
Serial.print (lesArrosages[a].dureeJusquaFinArrosage/1000);
Serial.print (F(" secondes , sur le pin : "));
Serial.println (lesArrosages[a].pinRelais);
}
}
}
}
void resetTimerArrosageAuto (t_commandID ID100) { // permet de relancer le prochain arrosage automatique
// ID100 est le numero de pin +100 , pas un index du tableau
uint8_t pin = ID100-100;
for (uint8_t a = 0; a < NOMBREDARROSAGE; a++) {
if (lesArrosages[a].pinRelais == pin ) {
if (lesArrosages[a].etat == ACTIF) {
resetZoneArrosee = true; // marque les zones a reinitialiser
lesArrosages[a].zoneArrosee = true; // marque la zone comme arrosee
if (!TEST) digitalWrite(lesArrosages[a].pinRelais, RELAIS_INACTIF); // relais off
lesArrosages[a].etat = INACTIF; // gestion etat
if (DEBUG) {
Serial.print (F("* resetTimerArrosageAuto => zoneArrosee "));
Serial.print (a);
Serial.print (F(" = "));
Serial.println (lesArrosages[a].zoneArrosee);
}
}
if (arrosageAutoON) {
calculDataArrosageAuto(&(lesArrosages[a]));
gestionnaireDeTache.registerAsyncCommand(ID100, lesArrosages[a].timerProchainArrosage, marcheArrosageAuto); // tourne en boucle , enregistre le prochain arrosage differe
// on active une nouvelle tache ayant pour id le numero de pin + 100 / le timer pour relancer le prochain arrosage / et la fonction automatique d ' arrosage pour callback .
if (DEBUG) {
Serial.print (F("* resetTimerArrosageAuto => Nouvelle tache enregistrée ayant pour ID : "));
Serial.print (ID100);
Serial.print (F(" pour durée :"));
Serial.println (lesArrosages[a].timerProchainArrosage);
}
}
else {
gestionnaireDeTache.unregisterAsyncCommand(ID100);
if (DEBUG) Serial.print (F("* resetTimerArrosageAuto => tache supprimée ! "));
}
}
}
}
void resetZoneArrosage () { // on reinitialise les zones arrosées pour le lendemain
if (resetZoneArrosee && (RTC.heure() >= HEURE_RESET_A)) {
resetZoneArrosee = false;
for (uint8_t a = 0; a < NOMBREDARROSAGE; a++) lesArrosages[a].zoneArrosee = false;
if (DEBUG) Serial.println (F("resetZoneArrosee => zones reinitialisees !"));
}
}
//// Fonctions de calculs : ////
void setSaison(t_commandID identifier) { // Gere le mode HORSGEL_ON *///////
if ((RTC.mois() == 3 && RTC.jour() >= 20) || RTC.mois() == 4 || RTC.mois() == 5 || (RTC.mois() == 6 && RTC.jour() < 20)) saison = PRINTEMPS;
else if ((RTC.mois() == 6 && RTC.jour() >= 20) || RTC.mois() == 7 || RTC.mois() == 8 || (RTC.mois() == 9 && RTC.jour() < 22)) saison = ETE;
else if ((RTC.mois() == 9 && RTC.jour() >= 22) || RTC.mois() == 10 || RTC.mois() == 11 || (RTC.mois() == 12 && RTC.jour() < 21)) saison = AUTOMNE;
else if ((RTC.mois() == 12 && RTC.jour() >= 21) || RTC.mois() == 1 || RTC.mois() == 2 || (RTC.mois() == 3 && RTC.jour() < 20)) saison = HIVER;
if (saison != 5) { // initialisation a 5 expres .
gestionnaireDeTache.registerAsyncCommand(identifier, 12 * TIMER_A, setSaison); // verifie 24 H apres si la saison n' a pas changé , ID 98
if (DEBUG) {
Serial.print (F("* setSaison => saison = "));
Serial.println (saison);
}
}
else {
gestionnaireDeTache.registerAsyncCommand(identifier, TIMER_V, setSaison); // on recommence dans 30 secondes .
if (DEBUG) {
Serial.print (F("* setSaison => saison = ERREUR !"));
}
}
}
void calculDataArrosageAuto (t_arrosage* unArrosage) { // l ' objectif est d ' espacer a intervalle de jours reguliers les arrosages des differentes zones en fonctions des saisons et de la zone a arroser
uint8_t nbJours = 0;
uint8_t HDA=0;
uint32_t convertJoursToMs = 24UL*60UL*60UL*1000UL; // Conversion en millisecondes
switch (saison) {
case PRINTEMPS :
coeffSaison = 1;
if (strcmp(unArrosage->nom, "Arbres") == 0 || strcmp(unArrosage->nom, "Fruitiers") == 0) {
nbJours = 7; // utile pour lancer le prochain arrosage via asynctask.
}
else if (strcmp(unArrosage->nom, "Haies") == 0 || strcmp(unArrosage->nom, "Jardin") == 0) {
nbJours = 5 ;
}
else if (strcmp(unArrosage->nom, "Bordures") == 0 || strcmp(unArrosage->nom, "Potager") == 0) {
nbJours = 2;
}
HDA=5;
break;
case ETE :
coeffSaison=1.5;
if (strcmp(unArrosage->nom, "Arbres") == 0 || strcmp(unArrosage->nom, "Fruitiers") == 0) {
nbJours = 4;
}
else if (strcmp(unArrosage->nom, "Haies") == 0 || strcmp(unArrosage->nom, "Jardin") == 0) {
nbJours = 3;
}
else if (strcmp(unArrosage->nom, "Bordures") == 0 || strcmp(unArrosage->nom, "Potager") == 0) {
nbJours = 1;
}
HDA=0;
break;
case AUTOMNE :
coeffSaison=1;
if (strcmp(unArrosage->nom, "Arbres") == 0 || strcmp(unArrosage->nom, "Fruitiers") == 0) {
nbJours = 7; // utile pour lancer le prochain arrosage via asynctask.
}
else if (strcmp(unArrosage->nom, "Haies") == 0 || strcmp(unArrosage->nom, "Jardin") == 0) {
nbJours = 5 ;
}
else if (strcmp(unArrosage->nom, "Bordures") == 0 || strcmp(unArrosage->nom, "Potager") == 0) {
nbJours = 2;
}
HDA=6;
break;
case HIVER : // voir avec temperature exterieure , sinon desactive
coeffSaison=0.5;
nbJours = 21;
HDA=12;
break;
default:
if (DEBUG) Serial.println(F("* => calculIntervalleJoursArrosage : ERREUR !!!"));
break;
}
unArrosage->dureeJusquaFinArrosage = (TIMER_A * coeffSaison);
unArrosage->joursIntervalle = nbJours;
unArrosage->timerProchainArrosage = convertJoursToMs * nbJours;
unArrosage->heureDebutArrosage = HDA;
if (DEBUG) {
Serial.print(F("* => calculIntervalleJoursArrosage : nbJours = "));
Serial.print(nbJours);
Serial.print(F(" , coeffSaison = "));
Serial.print(coeffSaison);
Serial.print(F(" , heureDebutArrosage = "));
Serial.print(unArrosage->heureDebutArrosage);
Serial.print(F(" , tempsDArrosage = "));
Serial.println(unArrosage->dureeJusquaFinArrosage);
}
}
/* mode auto */
//// FIN des Fonctions d ' arrosage : ////
//// Detecteurs ////
// detecteur de pluie
bool readPluieSensor () {
// mise en marche , attente , lecture puis arret du module :
// pour eviter la corrosion et limiter la consomation d ' energie.
// brancher sur un pin de sortie au lieu du 3.3 volts direct
static unsigned long chrono = 0;
static int value = -1; // jamais lu
if ((value == -1) || (millis() - chrono > TIMER_V)) { // si jamais lue ou lue depuis plus de 30 secondes
digitalWrite(PLUIE_SENSOR_VCC, RELAIS_ACTIF);
// Attente ??
value = analogRead(PLUIE_SENSOR_PIN);
digitalWrite(PLUIE_SENSOR_VCC, INACTIF);
chrono = millis();
value = 0;
}
return (map(value, 0, 1023, 0, 100) > SEUIL_PLUIE); // définir 990 et 300 en constantes globales serait mieux
}
// detecteur d' humidité du sol : humidity
// The sensor has a built-in potentiometer for sensitivity adjustment of the digital output (D0)
// All the resources for this project:
// https://randomnerdtutorials.com/
bool readHumiditySensor() {
// mise en marche , attente , lecture puis arret du module :
// pour eviter la corrosion et limiter la consomation d ' energie.
// brancher sur un pin de sortie au lieu du 3.3 volts direct
static unsigned long chrono = 0;
static int value = -1; // jamais lu
if ((value == -1) || (millis() - chrono > TIMER_V)) { // si jamais lue ou lue depuis plus de 30 secondes
digitalWrite(HUMIDITY_SENSOR_VCC, RELAIS_ACTIF);
// Attente ??
value = analogRead(HUMIDITY_SENSOR_PIN);
digitalWrite(HUMIDITY_SENSOR_VCC, INACTIF);
chrono = millis();
}
return (map(value, 0, 1023, 0, 100) > SEUIL_HUMIDITE); // définir 990 et 300 en constantes globales serait mieux
}
//// FIN Detecteurs ////
//// Fonctions d initialisation : ////
void initSDCard () { // disable enable SD Card
if (ENABLE_SDCARD) {
pinMode(SDCARD_PIN, OUTPUT);
digitalWrite(SDCARD_PIN, RELAIS_INACTIF);
if(DEBUG) {
Serial.print (F("* initSDCard => ENABLE_SDCARD : "));
Serial.println (ENABLE_SDCARD);
Serial.print (F("* initSDCard => SDCARD_PIN : "));
Serial.println (SDCARD_PIN);
}
}
else if(DEBUG) Serial.println (F("* No SDCard ."));
}
void initWebServer () { // Eth and UDP
if (ip != IPAddress(0,0,0,0) ) Ethernet.begin(MacAddress, ip); // demarrage du shield en IP static , On démarre le shield Ethernet
else if (Ethernet.begin(MacAddress) == 0) {
if (DEBUG) Serial.println (F("initWebServer => Failed to configure Ethernet using DHCP"));
// no point in carrying on, so do nothing forevermore:
for (;;)
;
}
else if (! int (Ethernet.begin(MacAddress))) { // Probleme de DHCP
if (DEBUG) Serial.println (F("initWebServer => NO DHCP"));
while (true); // stop here
}
webServer.begin();
Udp.begin(localPort);
if (DEBUG) printServerAddress();
}
void initGestionnaireDeTache () {
gestionnaireDeTache.registerAsyncCommand(99, TIMER_V/10, reglerHeureByNTP); // 3 secondes , le temps que le shield ethernet soit initialisé correctement . ensuite les reglages se passe directement dans la fonction .
delay(750);
gestionnaireDeTache.registerAsyncCommand(98, TIMER_V/10, setSaison); // 24 heures
}
void initSetupPluie () {
pinMode(PLUIE_SENSOR_PIN, INPUT);
pinMode(PLUIE_SENSOR_VCC, OUTPUT);
digitalWrite(PLUIE_SENSOR_VCC, RELAIS_INACTIF); // ACTIF OU PAS au demarrage ???
if(DEBUG) {
Serial.print (F("* initSetupPluie => PLUIE_SENSOR_PIN ( input ) : "));
Serial.println (PLUIE_SENSOR_PIN);
Serial.print (F("* initSetupPluie => PLUIE_SENSOR_VCC : "));
Serial.println (PLUIE_SENSOR_VCC);
}
}
void initSetupHumidity () {
pinMode(HUMIDITY_SENSOR_PIN, INPUT);
pinMode(HUMIDITY_SENSOR_VCC, OUTPUT);
digitalWrite(HUMIDITY_SENSOR_VCC, RELAIS_INACTIF); // ACTIF OU PAS au demarrage ???
if(DEBUG) {
Serial.print (F("* initSetupHumidity => HUMIDITY_SENSOR_PIN ( input ) : "));
Serial.println (HUMIDITY_SENSOR_PIN);
Serial.print (F("* initSetupHumidity => HUMIDITY_SENSOR_VCC : "));
Serial.println (HUMIDITY_SENSOR_VCC);
}
}
//// FIN Des Fonctions d ' initialisations ////
NOTE : les arrosages et les volets fonctionnent sur le meme principe que celui attendu des relais sans aucun soucis .
Pour les volets le code est de @J-M-L .
Pour info , avant que je modifie le code pour passer aussi par elle pour les relais , je l' avais ecrite comme cela :
void affecteCommandeWeb(bool b, t_volet* v=NULL, t_commandeVolet cv=NULL_V, t_arrosage* a=NULL, t_commandeArrosage ca=NULL_A)
{
commandeWeb.active=b; // bool
commandeWeb.volet=v;
commandeWeb.actionCMD_V=cv;
commandeWeb.actionCMD_A=ca;
commandeWeb.arrosage=a;
if (b) {
if (v) gererUnVolet(v);
else if (a) gererUnArrosage(a);
else if (ca == NULL_A && cv != NULL_V) gererLesVolets();
else if (cv == NULL_V && ca != NULL_A) gererLesArrosages();
}
}
Mais au final , si je me rapelle bien ( pas sur d ' avoir testé au final tellement j ' ai galeré avec ce truc là ) ,en ajoutant et en gardant le meme principe , ca ne fonctionnait pas non plus .
je vais refaire un test , sait on jamais .
ci joint le zip complet du code , si vous preferez :
serveur_machine_etats_7.330.zip (21.9 KB)