#include <DS3232RTC.h> // http://github.com/JChristensen/DS3232RTC
#include <TimeLib.h> // http://playground.arduino.cc/Code/Time (presente in gestione)
#include <Wire.h> // http://arduino.cc/en/Reference/Wire (vedi sopra – see above)
#include <LiquidCrystal_I2C.h> // libreria di gestione del display lcd
#include <DHT.h>
#define DEBUG true // Scrive log su uscita seriale
#define SIMULAZIONE true // Usa simulatore online WOKWI
#if SIMULAZIONE == true
#define DHTTYPE DHT22
#define lcd_address 0x27
#else
#define DHTTYPE DHT11
#define lcd_address 0x3F
#endif
// ======================================================================================================
// ========================================= PARAMETRI UTENTE ===========================================
// ======================================================================================================
const int MILLISECONDI_TRA_CAMBIO_VISTA = 4000; // millisecondi tra schermate
const unsigned int ValOra_Alm1 = 18; // Variabile inizio ora EV1 (0 - 23)
const unsigned int ValMin_Alm1 = 42; // Variabile inizio minuti EV1 (0 - 59)
const unsigned int Durata_Alm1 = 15; // Variabile durata attivazione EV1 in minuti (0 - 59)
const unsigned int Cadenza_Alm1 = 1; // Ogni quanti giorni dal 1/1/1970
const unsigned int ValOra_Alm2 = 18; // Variabile inizio ora EV2 (0 - 23)
const unsigned int ValMin_Alm2 = 43; // Variabile inizio minuti EV2 (0 - 59)
const unsigned int Durata_Alm2 = 6; // Variabile durata attivazione EV2 in minuti (0 - 59)
const unsigned int Cadenza_Alm2 = 1; // Ogni quanti giorni dal 1/1/1970
// ======================================================================================================
// ======================================================================================================
// ======================================================================================================
/* Note su gestione uscite Timer 2 zone con 2 EValvole la EV1 bistabile a 9V. si eccita con impulso > 50ms dato con Ou13 a "1" e Out 11 a "0"
e si resetta invertendo gli stati delle 2 uscite, * altre combinazioni delle 2 uscite non creano variazioni di stato.
La Ev2 è monostabile e viene attivata per la durata programmata da un relé (escluso utilizzo relè passo-passo pensato inizialmente)
*/
const char mesiDellAnno[12][4] = {"Gen", "Feb", "Mar", "Apr", "Mag", "Giu", "Lug", "Ago", "Set", "Ott", "Nov", "Dic"};
const unsigned int pinSettore1_attiva = 11; // Uscita deve essere a livello "1- attiva" mentre contemporaneamente Out 13 deve essere a livello "0-disattiva" per Settare la EV1
const unsigned int pinSettore1_spegni = 13; // Uscita deve essere a livello "1- attiva" mentre contemporaneamente Out 11 deve essere a livello "02 per Reset della EV1
const unsigned int pinSettore2 = 10; // Uscita di Set per EV2 a 24V (l'uscita 12 non funziona ed è stata esclusa dal collegamento)
const unsigned int DHTPIN = 7; // Pin D7 su cui è collegato l'output del sensore DHT
const unsigned int buttonPin1 = 2; // Pulsante nero lettura dati timer 1 x Ev1
const unsigned int buttonPin2 = 3; // Pulsante rosso lettura dati timer 2 x Ev2
const unsigned int ledPin1 = 4; // Led stato Ev1 (acceso=attiva)
const unsigned int ledPin2 = 5; // Led stato Ev2 (acceso=attiva)
/* Selector pins and logic
14 * * 1 1 0
15 * * 1 0 *
16 1 1 0 0 0
17 1 0 * * *
auto off ambo ev1 ev2
*/
const unsigned int Selettore2_pos_1e3 = 14;
const unsigned int Selettore2_pos_2e3 = 15;
const unsigned int Selettore1_pos_1e2 = 16;
const unsigned int Selettore1_pos_1e3 = 17;
LiquidCrystal_I2C lcd(lcd_address, 16, 2); // indirizzo del modulo LCD e n.caratteri e righe
DHT dht(DHTPIN, DHTTYPE);
DS3232RTC RTC;
// Inizializzazioni statistiche di temperatura del giorno
float minima_giorno_temperatura = 999.9;
unsigned int minima_giorno_ora = 0;
unsigned int minima_giorno_minuti = 0;
float massima_giorno_temperatura = -999.9;
unsigned int massima_giorno_ora = 0;
unsigned int massima_giorno_minuti = 0;
// Inizializzazioni altri controlli
unsigned int pulsante_premuto = 0;
long nuovo_timer_cambia_vista_normale = 0;
long vecchio_timer_cambia_vista_normale = 0;
bool elettrovalvola1_accesa = false;
bool elettrovalvola2_accesa = false;
bool flag_mostra_orologio = true; // durante vista normale (pulsante_premuto=0) questa variabile definisce
// se si mostri l'orologio o la temperatura e umidità
/* Le variabili che seguono servono per impostare ora e minuti per attivazione uscite Ev1 e Ev2 e durata
dell'attivazione, nel programma definitivo tutti i dati dovrebbero essere impostabili su display */
unsigned int allarme1_inizio_in_minuti;
unsigned int allarme1_fine_in_minuti;
unsigned int allarme2_inizio_in_minuti;
unsigned int allarme2_fine_in_minuti;
bool allarme1_attivo = false;
bool allarme2_attivo = false;
void setup(void) {
Serial.begin(9600); // inizializza il monitor seriale
console("Entrato nella routine setup\n");
lcd.begin(16, 2); // inizializza il display e accende
lcd.backlight(); // lo sfondo
lcd.print(" Buongiorno"); // messaggio iniziale
delay(1500);
lcd.clear();
setSyncProvider(RTC.get); // sincronizza il timer di Arduino con i dati presenti
lcd.print(" Orologio");
if (timeStatus() != timeSet) {
lcd.print(" NON");
}
lcd.setCursor(0, 1);
lcd.print (" sincronizzato");
delay(1500);
/* Note di utilizzo del modulo RTC DS3231 orologio digitale con batteria
Questo programma sincronizza il timer interno di arduino con la
data e l'ora fornita da un orologio esterno (un modulo RTC con
DS3231) ed espone data, ora e temperatura su di un display 1620
Per caricare sul modulo RTC la data e l'ora corrente
utilizzando la tastiera del pc collegato ad arduino via cavo USB.
utilizzare il programma di esempio della libreria DS3232RTC che si chiama SetSerial.ino
caricarlo su Arduino poi aprire il serial monitor impostare in basso il baud rate di 115200 e digitare in sequenza
aa,mm,gg,hh,mm,ss,
dove aa anno, sottoforma di due caratteri (2016 = 16), mm mese, da 1 a 12, gg giorno, da 1 a 31
hh ora, da 00 a 23 , mm minuti, da 0 a 59, ss secondi, da 0 a 59 seguito da un'ultima virgola
Nel momento in cui viene immessa la stringa (nel momento in cui si
preme enter), l'orologio inizia a computare il tempo partendo dai dati immessi e non avra' piu' bisogno
di essere settato (a meno che non si scarichi la pila o la si tolga) */
//Avvio trasmissione sensore DHT 11
dht.begin();
// definizione Pulsanti e Led e ingressi selettori modo funzionamento
pinMode(ledPin1, OUTPUT);
pinMode(ledPin2, OUTPUT);
pinMode(buttonPin1, INPUT);
pinMode(buttonPin2, INPUT);
pinMode(Selettore1_pos_1e3, INPUT_PULLUP); //IN17
pinMode(Selettore1_pos_1e2, INPUT_PULLUP); //IN16
pinMode(Selettore2_pos_2e3, INPUT_PULLUP); //IN15
pinMode(Selettore2_pos_1e3, INPUT_PULLUP); //IN14
allarme1_inizio_in_minuti = ValOra_Alm1 * 60 + ValMin_Alm1;
allarme1_fine_in_minuti = allarme1_inizio_in_minuti + Durata_Alm1;
allarme2_inizio_in_minuti = ValOra_Alm2 * 60 + ValMin_Alm2;
allarme2_fine_in_minuti = allarme2_inizio_in_minuti + Durata_Alm2;
// definizione uscite per Ev1 e Ev2
pinMode( pinSettore1_attiva, OUTPUT);
pinMode( pinSettore1_spegni, OUTPUT);
pinMode( pinSettore2, OUTPUT);
// Inizializza a livello inattivo le uscite legate a EV1 e EV2
digitalWrite(pinSettore1_attiva, LOW);
digitalWrite(pinSettore1_spegni, LOW);
digitalWrite(pinSettore2, LOW);
}
int controlla_quale_pulsante_premuto() {
int buttonState1 = digitalRead(buttonPin1);
int buttonState2 = digitalRead(buttonPin2);
if (buttonState1 == HIGH and buttonState2 == HIGH)
return 3;
else if (buttonState1 == HIGH)
return 1;
else if (buttonState2 == HIGH)
return 2;
else
return 0;
}
void mostra_orologio_su_lcd() {
// esposizione dei dati rilevati sul timer di arduino DS3231
String _ore_minuti = stringa_ore_minuti(hour(), minute());
int temp_C = RTC.temperature() / 4.0; // rileva la temperatura e trasforma in gradi celsius
String giorno_str = String(day());
String mese_str = mesiDellAnno[month()];
String anno_str = String(year());
lcd.clear();
lcd.print(' '+giorno_str+' '+mese_str+' '+anno_str);
lcd.setCursor(0, 1);
lcd.print(_ore_minuti+" t:");
lcd.print(temp_C, 1);
}
//****routine visualizzazione minuti e secondi comprensivi di zeri non significativi*****
String stringa_ore_minuti(int ora, int minuto){
String ora_str = ( ora < 10 ) ? ('0'+ String(ora)) : String(ora);
String minuto_str = ( minuto < 10 ) ? ('0'+ String(minuto)) : String(minuto);
return ora_str + ':' + minuto_str;
}
void mostra_temperatura_umidita_su_lcd() {
float h = dht.readHumidity();
float t = dht.readTemperature();
// Verifica se qualche lettura DHT11 ha dato errore in tal caso esce per ripetere la lettura di nuovo
if (isnan(h) || isnan(t)) {
lcd.clear();
lcd.println("ERR.lettura DHT11");
} else {
lcd.clear();
lcd.print("Umidita % : ");
lcd.print(h, 0);
lcd.setCursor(0, 1);
lcd.print("Temp.est : ");
lcd.print(t, 1);
}
}
void mostra_orologio_temperature_umidita(bool mostra_orologio) {
if (mostra_orologio) {
mostra_orologio_su_lcd();
} else {
mostra_temperatura_umidita_su_lcd();
}
}
void mostra_impostazioni(String nome, int ore, int minuti, int durata) {
String _ore_minuti = stringa_ore_minuti(ore, minuti);
lcd.clear();
lcd.print(nome + " attiva alle:");
lcd.setCursor(0, 1);
lcd.print(_ore_minuti+" x "+String(durata)+" Min.");
}
bool controlla_tempo_contro_allarmi(int allarme_inizio, int allarme_fine) {
int adesso_in_minuti = hour() * 60 + minute();
if ((adesso_in_minuti >= allarme_inizio) and (adesso_in_minuti < allarme_fine)) {
return true;
} else {
return false;
}
}
void accendi_ev1() {
if (elettrovalvola1_accesa == false) {
digitalWrite(pinSettore1_attiva, HIGH);
digitalWrite(pinSettore1_spegni, LOW);
delay(100);
digitalWrite(pinSettore1_attiva, LOW);
elettrovalvola1_accesa = true;
digitalWrite(ledPin1, HIGH);
}
}
void spegni_ev1() {
if (elettrovalvola1_accesa == true) {
digitalWrite(pinSettore1_spegni, HIGH);
digitalWrite(pinSettore1_attiva, LOW);
delay(100);
digitalWrite(pinSettore1_spegni, LOW);
elettrovalvola1_accesa = false;
digitalWrite(ledPin1, LOW);
}
}
void accendi_ev2() {
if (elettrovalvola2_accesa == false) {
digitalWrite(pinSettore2, HIGH);
elettrovalvola2_accesa = true;
digitalWrite(ledPin2, HIGH);
}
}
void spegni_ev2() {
if (elettrovalvola2_accesa == true) {
digitalWrite(pinSettore2, LOW);
elettrovalvola2_accesa = false;
digitalWrite(ledPin2, LOW);
}
}
void controllo_elettrovalvola_1() {
if (elettrovalvola1_accesa == false and allarme1_attivo) {
accendi_ev1();
} else if (elettrovalvola1_accesa == true and not allarme1_attivo) {
spegni_ev1();
}
}
void controllo_elettrovalvola_2() {
if (elettrovalvola2_accesa == false and allarme2_attivo) {
digitalWrite(pinSettore2, HIGH);
elettrovalvola2_accesa = true;
digitalWrite(ledPin2, HIGH);
} else if (elettrovalvola2_accesa == true and not allarme2_attivo) {
digitalWrite(pinSettore2, LOW);
elettrovalvola2_accesa = false;
digitalWrite(ledPin2, LOW);
}
}
void mostra_statistiche_temperatura() {
lcd.clear();
lcd.print("Tmin:");
lcd.print(minima_giorno_temperatura, 1);
lcd.print(" @");
lcd.print(stringa_ore_minuti(minima_giorno_ora, minima_giorno_minuti));
lcd.setCursor(0, 1);
lcd.print("Tmax:");
lcd.print(massima_giorno_temperatura, 1);
lcd.print(" @");
lcd.print(stringa_ore_minuti(massima_giorno_ora, massima_giorno_minuti));
}
void calcola_statistiche_temperatura() {
console("Entrato nel calcolo delle statistiche\n");
if (hour() == 0 and minute() == 0) {
massima_giorno_temperatura = -999.9;
minima_giorno_temperatura = 999.9;
}
float temperatura_attuale = dht.readTemperature();
if (not isnan(temperatura_attuale)) {
if (temperatura_attuale > massima_giorno_temperatura) {
massima_giorno_temperatura = temperatura_attuale;
massima_giorno_ora = hour();
massima_giorno_minuti = minute();
}
if (temperatura_attuale < minima_giorno_temperatura) {
minima_giorno_temperatura = temperatura_attuale;
minima_giorno_ora = hour();
minima_giorno_minuti = minute();
}
}
}
void mostra_selettore_in_spento() {
lcd.setCursor(0, 0);
lcd.print("Selet. su SPENTO");
lcd.setCursor(0, 1);
lcd.print(" NO Irrigazione ");
}
void mostra_selettore_su_comandi_manuali() {
lcd.setCursor(0, 0);
lcd.print("Comandi Manuali ");
lcd.setCursor(0, 1);
lcd.print("Attiva EV Manuale");
}
String esegui_secondo_stato_selettori() {
String stato_selettori = "NA";
if (digitalRead(Selettore1_pos_1e2) == HIGH){
if (digitalRead(Selettore1_pos_1e3) == HIGH){
routine_automatica();
stato_selettori = "Auto";
} else {
spegni_ev1();
spegni_ev2();
stato_selettori = "Off";
mostra_selettore_in_spento();
}
} else {
if (digitalRead(Selettore2_pos_1e3) == HIGH){
if (digitalRead(Selettore2_pos_2e3) == HIGH){
accendi_ev1();
accendi_ev2();
stato_selettori = "Ambo On";
} else {
accendi_ev1();
spegni_ev2();
stato_selettori = "Ev1 On";
}
} else {
accendi_ev2();
spegni_ev1();
stato_selettori = "Ev2 On";
}
mostra_selettore_su_comandi_manuali();
}
return stato_selettori;
}
void mostra_stato_pin(){
for (int thisPin = 14; thisPin < 18; thisPin++) {
console("pin "+String(thisPin)+" status: "+String(digitalRead(thisPin))+"\n");
}
// for (int thisPin = 1; thisPin < 20; thisPin++) {
// console("pin "+String(thisPin)+" status: "+String(digitalRead(thisPin))+"\n");
// }
}
void routine_automatica() {
console("Entrato nella routine automatica\n");
pulsante_premuto = controlla_quale_pulsante_premuto();
switch (pulsante_premuto) {
case 0: // Vista Normale
nuovo_timer_cambia_vista_normale = millis() % MILLISECONDI_TRA_CAMBIO_VISTA;
if (nuovo_timer_cambia_vista_normale < vecchio_timer_cambia_vista_normale) {
// commutazione della vista normale tra orologio e Temperatura&Umidità
flag_mostra_orologio = not flag_mostra_orologio;
mostra_orologio_temperature_umidita(flag_mostra_orologio);
}
vecchio_timer_cambia_vista_normale = nuovo_timer_cambia_vista_normale;
break;
case 1:
mostra_impostazioni("EV1", ValOra_Alm1, ValMin_Alm1, Durata_Alm1);
vecchio_timer_cambia_vista_normale = millis() % MILLISECONDI_TRA_CAMBIO_VISTA;
break;
case 2:
mostra_impostazioni("EV2", ValOra_Alm2, ValMin_Alm2, Durata_Alm2);
vecchio_timer_cambia_vista_normale = millis() % MILLISECONDI_TRA_CAMBIO_VISTA;
break;
case 3: //entrambi i pulsanti
mostra_statistiche_temperatura();
break;
}
// controllo allarmi e invio segnali a elettrovalvole eseguito solo se selettore in posizione Auto
allarme1_attivo = controlla_tempo_contro_allarmi(allarme1_inizio_in_minuti, allarme1_fine_in_minuti);
allarme2_attivo = controlla_tempo_contro_allarmi(allarme2_inizio_in_minuti, allarme2_fine_in_minuti);
controllo_elettrovalvola_1();
controllo_elettrovalvola_2();
}
void loop(void) {
String stato_selettori = esegui_secondo_stato_selettori();
console("stato_selettori: "+stato_selettori+"\n");
calcola_statistiche_temperatura(); // effettuato anche con selettore in manuale
mostra_stato_pin();
}
void console(String messaggio){
if(DEBUG == true){
Serial.print(messaggio);
}
}