/*----------------------------------------------------------------------*/
//
// Acquisizione dati Macchina di Savery con ESP32
// Con invio dati a Server Pyton tramite
// Sockets (A.Barone 24 Settembre 2025)
// Versione 1.02
//
/*----------------------------------------------------------------------*/

#include <string.h>
#include <WiFi.h>

// ------------------- Dichiarazione dei Timers ------------------------------
hw_timer_t *timer_1ms = NULL; // Inizializzazione Timer Acquisizione da Flussimetri 1 mSec
hw_timer_t *timer_2s = NULL; // Inizializzazione Timer Memorizzazione dati 1/2 Sec

// ------------------- Dichiarazione delle porte dell'ESP32 ------------------------------
#define LED1 13 // Led Lampeggiante
#define LED2 12 // Led Run/Stop
#define LED3 14 // Led WiFi
#define LED4 27 // Overload

#define PL1 26 // Pulsante acquisizione dati, Start/Stop
#define FLS1 25 // Ingresso Flussimetro 1
#define FLS2 33 // Ingresso Flussimetro 2
#define PRS1 32 // Ingresso Pressostato

// ------------------- Dichiarazione delle Costanti Globali ------------------------------
#define CICLI_MAX 40 // Numero Massimo delle acquisizioni

// -------- Variabili per il Led Lampeggiante ---------
int ll = 0; // Contatore dei cicli on/off
int lamp = 0; // Stato attuale


// -------- Variabili per il Server di WiFi --------- //
char ssid[] = "WIFI_NAME"; // SSID di rete
char password[] = "password"; // Password di Reete

WiFiClient wclient; // Istanza alla classe WiFi


//---------- Variabili per il salvataggio su Server ----------------------------
const uint16_t port = 10000; // Soket tcp/ip Port file Flussimetro1
const uint16_t port1 = 10001; // Soket tcp/ip Port file Flussimetro2
const uint16_t port2 = 10002; // Soket tcp/ip Port file Pressostato

const char * host = "192.168.1.181"; // Ip del vostro Server Python
char uscita[5000]; // buffer Flussimetro 1
char uscita1[5000]; // buffer Flussimetro 2
char uscita2[5000]; // buffer Pressostato


// Impostazione dei Contatori
uint32_t Flow1Counter = 0; // Contatore Flussimetro 1
uint32_t Flow2Counter = 0; // Contatore Flussimetro 2

uint16_t cicli = 0; // Contatore dei cicli
//---------------------------


// ----- Dichiarazione delle Variabili di Stato -----
bool fluss1_now = false;
bool fluss2_now = false;
bool fluss1_old = false;
bool fluss2_old = false;
int press_now = 0;
bool start_acquisizione = false; // False: spento, true; acquisisco
bool pl1_old_status = false; // stato precedente del pulsante
bool stop_acquisizione = false; // Serve a segnalare la pressione prima che venga terminato il ciclo
bool sent_data = true; // Vine posto a true dopo aver inviato l'acquisizione
bool tr_error = false; // Errore di trasmissione al server
bool error_status = false;


/* Dichiarazione delle funzioni esternre che trovate sotto il main loop. Se si vogliono scrivere in basso al codice
Devono essere dichiarate prima del programma altrimenti il compilatore non le trova. Per un maggiore ordine nella
scrittura del codice le ho messe sotto */

void IRAM_ATTR onTimer_1ms(); // ------------- Funzione Primo Timer
void IRAM_ATTR onTimer_2s(); // ------------- Funzione Secondo Timer
void initWiFi(char *ssid,char *password); // ------------- Funzione WiFi
int lampeggia(int led, int k2, int *lamp, int periodo); // ------------- Funzione Per il lampeggio del Led
void ControlloPressionePulsante(); // ------------- Funzione Controllo pressione
void TrasmissioneDatiAlServer(); // ------------- Funzione Trasmissione Dati

/* ------------- Fine dichiarazione delle funzioni -------------------*/

/*------------------ Setup principale -----------------*/
void setup()
{
Serial.begin(9600); // inizializzazione della seriale di monitor

// inizializzazione dei led
pinMode(LED1, OUTPUT); // blinking Led
pinMode(LED2, OUTPUT); // led di segnalazione attività di campionamento
pinMode(LED3, OUTPUT); // led connessione HiFi
pinMode(LED4, OUTPUT);

digitalWrite(LED1, LOW); //spegnimento led (condizione Iniziale)
digitalWrite(LED2, LOW); //spegnimento led (condizione Iniziale)
digitalWrite(LED3, LOW); //spegnimento led (condizione Iniziale)
digitalWrite(LED4, LOW); //spegnimento led (condizione Iniziale)

// inizializzazione delle porte di input - output
pinMode(PL1, INPUT); // Pulsante e/o sensore
pinMode(FLS1, INPUT); // Flussimetro 1
pinMode(FLS2, INPUT); // Flussimetro 2
pinMode(PRS1, INPUT); // Pressostato

// Inizializzazione dei Timers
timer_1ms = timerBegin(1000000); // Timer 1 Acquisizione da sensori
timerAttachInterrupt(timer_1ms, &onTimer_1ms);
timerAlarm(timer_1ms, 10000, true, 0); // intervallo 1/100 secondo

timer_2s = timerBegin(1000000); // Timer 2 Salvataggio dati nel buffer
timerAttachInterrupt(timer_2s, &onTimer_2s);
timerAlarm(timer_2s, 1000000, true, 0); // intervallo 1 secondo

//inizializzazione WiFi
initWiFi(ssid, password);

Serial.println("Setup terminato"); //messaggio di fine configurazione
}
/*------------------ Fine Setup principale -----------------*/

/*------------------ Lopp principale -----------------*/
void loop()
{
ll = lampeggia(LED1,ll,&lamp,1000000); // Eseguo Settaggio stato led lampeggiante
 
ControlloPressionePulsante(); // Controllo se è stato premuto il pulsante per
// Iniziare l'acquisizione

TrasmissioneDatiAlServer(); // Trasmetto i dati al server Se necessario
}

/* ------------- Funzione Trasmissione Dati Al Server ------------------*/
void TrasmissioneDatiAlServer()
{
if( ( stop_acquisizione == true ) and ( sent_data == false ) ) // se il pulsante è stato premuto inizio le misurazioni
{
digitalWrite(LED4, HIGH); // Accendo il led di salvataggio
// Invio primo file al server
if(!wclient.connect(host, port)) //controllo se il server è disponibile
{
Serial.println("Connection to host failed");
tr_error = true;
}
else
{
wclient.print(uscita); //invio i dati al server
wclient.stop();
Serial.println("\nend");
}
Serial.println(" Primo file scritto");


// Invio secondo file al server
if(!wclient.connect(host, port1)) //controllo se il server è disponibile
{
Serial.println("Connection to host failed");
tr_error = true;
}
else
{
wclient.print(uscita1); //invio i dati al server
wclient.stop();
Serial.println("\nend");
}

// Invio secondo file al server
if(!wclient.connect(host, port2)) //controllo se il server è disponibile
{
Serial.println("Connection to host failed");
tr_error = true;
}
else
{
wclient.print(uscita2); //invio i dati al server
wclient.stop();
Serial.println("\nend");
}
 
 
uscita[0] = '\0'; //pulisco il buffer
uscita1[0] = '\0'; //pulisco il buffer
uscita2[0] = '\0'; //pulisco il buffer

stop_acquisizione = false;
start_acquisizione = false;
sent_data = true;
cicli = 0;
digitalWrite(LED4, LOW); // Spengo il led di salvataggio
}
}
/* ------------- Fine Funzione Trasmissione Dati Al Server ------------------*/


/* ------------- Funzione Controllo pressione del pulsante ------------------*/
void ControlloPressionePulsante()
{
if(digitalRead(PL1) == LOW) // controllo se il pulsante è premuto
{
if(pl1_old_status == false)
{
start_acquisizione = true;
stop_acquisizione = false;
cicli = 0; // Azzero il contatore
pl1_old_status = true;
digitalWrite(LED2, HIGH); // Accendo il led di acquisizione
Serial.println("Pulsante premuto"); // Commento di Debug
}
else
{
start_acquisizione = false;
stop_acquisizione = true;
digitalWrite(LED2, LOW); // Spengo il led di acquisizione
pl1_old_status = false;
 
}
digitalWrite(LED4, LOW); // Spengo il led di mancato salvataggio
tr_error = false;
sent_data = false;
delay(500);
}
}
/* ------------- Fine Funzione Controllo pressione del pulsante ------------------*/




/* ------------- Funzione Primo Timer ------------------*/
void IRAM_ATTR onTimer_1ms() // un millisecondo
{
fluss1_now = digitalRead(FLS1); // Lettura del primo flussimetro
if( fluss1_now != fluss1_old )
{
Flow1Counter++;
fluss1_old = fluss1_now;
}

fluss2_now = digitalRead(FLS2); // Lettura del secondo flussimetro
if( fluss2_now != fluss2_old )
{
Flow2Counter++;
fluss2_old = fluss2_now;
}

}
/* ------------- Fine Funzione Primo Timer ------------------*/

/* ------------- Funzione Secondo Timer ------------------*/
void IRAM_ATTR onTimer_2s() // mezzo secondo
{
if(start_acquisizione and cicli <= CICLI_MAX)
{
cicli++;

// memorizzo la lettura del flussimetro 1
String str = String(Flow1Counter); // Coonverto il valore letto in stringa
char *p = const_cast<char*>(str.c_str()); //conversione della stringa per poter usare la funzione strcat()
strcat(uscita, p); //aggiungo la misura al buffer di uscita
strcat(uscita,";"); // aggiungo il ; qule separatore per il formato csv

// memorizzo la lettura del flussimetro 2
str = String(Flow1Counter); // Coonverto il valore letto in stringa
p = const_cast<char*>(str.c_str()); //conversione della stringa per poter usare la funzione strcat()
strcat(uscita1, p); //aggiungo la misura al buffer di uscita
strcat(uscita1,";"); // aggiungo il ; qule separatore per il formato csv

// memorizzo la lettura del pressostato
uint32_t potValue = analogRead(PRS1);
str = String(potValue); // Coonverto il valore letto in stringa

p = const_cast<char*>(str.c_str()); //conversione della stringa per poter usare la funzione strcat()
strcat(uscita2, p); //aggiungo la misura al buffer di uscita
strcat(uscita2,";"); // aggiungo il ; qule separatore per il formato csv
Serial.println("\n ciclo n°");
Serial.println(cicli);
}
else
{
if(cicli == (CICLI_MAX+1))
{
stop_acquisizione = true;
pl1_old_status = false;
}
sent_data = false;
start_acquisizione = false;
digitalWrite(LED2, LOW); // Spengo il led di acquisizione
}
if(tr_error)
{
if(error_status)
{
digitalWrite(LED4, HIGH);
error_status = !error_status;
}
else
{
digitalWrite(LED4, LOW);
error_status = !error_status;
}
}
}
/* ------------- Fine Funzione Secondo Timer ------------------*/


/*------------------------------------------------------*/
/*------- funzione di inizializzazione delle wifi ------*/

void initWiFi(char *ssid,char *password)
{
if (WiFi.status() != WL_CONNECTED)
{
Serial.println("Starting wifi");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);int VoltsValue=0;
Serial.print(".");
}
// Serial.println("");
digitalWrite(LED3, HIGH);
Serial.println("WiFi connected");
}
}
/*------------------------------------------------------*/
/*----------- Funzione del led lampeggiante ------------*/
int lampeggia(int led, int k2, int *lamp, int periodo)
{
k2++;
if (k2 == periodo and *lamp == 0)
{
digitalWrite(led, HIGH); // turn the LED on
*lamp=1;
k2 = 0;
}

if (k2 == (periodo+1) and *lamp == 1)
{
digitalWrite(led, LOW); // turn the LED on
*lamp=0;
k2 = 0;
}
return k2;
}
/*------------------------------------------------------*/