Aggiunta caratteri ÿ in upload FTP se alimentato a muro

Ciao a tutti,
posto con orgoglio questo messaggio perchè sono finalmente arrivato a fare quello che volevo e cerco di spiegare l'ultimo scoglio che mi affligge sperando in qualche idea o workaround che mi possa essere d'aiuto.

Specifiche:
ARDUINO UNO R4 WIFI
BME280 (Termometro e misuratore di pressione atmosferica)
DS3231 (Real time clock)
MemoryCard SPI per Arduino

Obiettivo del progetto:
Rilevare la temperatura della casetta degli attrezzi che ho in giardino poichè ci metterò delle piante molto sensibili alle basse temperature.
Salvare i valori su file in un file giornaliero con un tracciato da me definito.
Quando è disponibile una rete WIFI di casa (ne ho 5 ma le accendo a singhiozzo per vari motivi ed esigenze che qui sono off topic) deve:

  • effettuare l'upload dei file con i dati su internet via FTP su un mio spazio Altervitsa.
  • scaricare dallo stesso spazio Altervista i file di configurazione T_Max e T_Min assieme ad altri così che possa comandare Arduino, anche se in differita, cambiando i valori a mio piacere (p.es a seconda della stagione).

Quando la temperatura scende sotto la soglia T_Min manda una notifica telegram (così posso ritirare le piante in casa per evitare le gelate) oppure quando la temperatura sale sopra la soglia T_Max da me impostata manda comunque una notifica telegram.
Poter usare Google Charts per elaborare il file di testo (che è di fatto un csv) e creare il grafico che mi mostra i dati raccolti.
Accendere un led quando devo attivare la stufa a mano, accendere un led quando devo accedere a mano la luce apposta per le piante.
Usare la matrice a led per farmi dire cosa sta facendo la macchina o eventuali errori con un messaggio quanto più parlante possibile.

Questo il tracciato del file alimentato da parete :

2024;08;04;02;17;49;26.45;98363.62;5480;26.00;26.50;28.00;0;0
2024;08;04;02;18;24;26.45;98360.73;5480;26.ÿ00;26.50;28.00;0;0
2024;08;04;02;18;50;26.43;98363.44;5480;26.00;26.50;28.00;0;0
2024;08;04;02;19;20;26.44;98359.27;5480;26.00;26.50;28.00;0;0
2024;08;04;02;20;50;26.44;98361.76;5480;26.00;26.50;28.00;0;0
2024;08;04;02;21;20;26.44;98365.40;5480;26.00;26.50;28.00;0;0
2024;08;04;02;21;51;26.47;98361.79;5480;26.00;26.50;28.00;0;0
2024;08;04;02;22;21;26.49;98360.07;5480;26.00;26.50;28.00;0;0
2024;08;04;02;22;51;26.51;98359.79;5480;26.00;26.50;28.00;0;0
2024;08;04;02;23;21;26.53;98364.31;5480;26.00;26.50ÿ;28.00;0;0
2024;08;04;02;23;51;26.56;98359.80;5480;26.00;26.50;28.00;0;0

Si vedono le ÿ di troppo che mi disallineano il file e mi creano problemi col grafico.

A volte il risultato è nettamente peggiore con tantissimi caratteri che non esistono nel file sulla SD (tolta da Arduino aperta da PC), come ad esmepio questo:

2024;08;08;00;27;47;25.71;98628.42;5356;21.00;21.50;30.00;0;0
2024;08;08;00;28;17;25.70;98628.84;5356;21.00;21.50;30.0ے0;0;0
2024;08;08;00;28;47;25.70;98626.29;5356;21.00;21.50;30.00;0;0
2024;08;08;00;29;17;25.68;98632.45;5356;21.00;21.50;30.00;0;0
2024;08;08;00;29;47;25.66;98632.33;5356;21.00;21.50;30.00;0;0
2024;08;08;00;30;17;25.65;98633.77;5356;21.00;21®50;َ0>?ےû?؟ےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےےے024;08;08;00;32;47;25.68;98632.53;5356;21.00;21.50;30.00;0;0
2024;08;08;00;33;17;25.67;98631.60;5356;21.00;21.50;30.00;0;0
2024;08;08;00;33;47;25.67;98630.39;5356;21.00;21.50;30.00;0;0

Ottengo questo pessimo risultato solo cambiando l'alimentazione :

  • da PC va sempre tutto bene. Un test di 13 giorni di fila non ha rilevato alcun problema.
  • con alimentazione alla parete arrivano le ÿ nel file destinazione.

Specifico che la zona della misura è sempre la stessa, nel raggio di pochi centimetri. Lo dico perchè ho pensato ad interferenze elettromagnetiche.
Il cavo che uso in entrambi i casi è sempre lo stesso.
Il codice che uso, è ovvio ma lo scrivo, è sempre lo stesso. Alla fine del post il codice completo.
La rete WIFI che ho usato per le prove è sempre la stessa , nonostante le 5 alternabili, e l'access point WIFI è sempre uguale ed è sempre nello stesso punto.

Ecco il codice:


#include <Arduino_LED_Matrix.h>
#include <WiFiS3.h>
#include <SD.h>
#include <Wire.h>                             //Avvio comunicazione I2C
#include <BMx280I2C.h>
#include <uRTCLib.h>
#include <SPI.h>
#include <AsyncTelegram2.h>

// ****************
// Custom include
// ****************
#include "arduino_secrets.h"
#include "coda_led.h"
#include "ftp_led.h"
#include "sd_led.h"
#include "err_led.h"




// ***********
// Definizioni
// ***********
#define HEADER_SIZE 1024                                              // Buffer size definitions per il download dei file
#define BODY_SIZE 256                                                 // Buffer size definitions per il download dei file
#define WEB_SERVER "www.<mio_sito>.altervista.org"                 // Web server per il download dei file
#define I2C_bmx280_ADDRESS 0x76
#define I2C_RTC_ADDRESS 0x68
#define IMPLEMENTATION  FIFO                                          // Gestione della pila per la coda Telegram : First In First Out


// **********
// Costanti
// **********
//int intervallo_ciclo_secondi = 30;                                        // CICLO PRINCIPALE (misura temperatura)
int intervallo_rilevazione_temp_secondi = 60;                                        // CICLO PRINCIPALE (misura temperatura)
int intervallo_download_file_config_minuti = 14;
int intervallo_di_rilevazione_wifi_minuti = 1;
int intervallo_di_upload_FTP_minuti = 9;                               // Minuti tra due upload FTP del file del giorno corrente
int intervallo_di_notifica_temperatura_telegram_minuti = 30 ;         // secondi minimi tra due notifiche telegram successive


// Flag 
bool serial_avail = false;
bool ConnessoInPassato = false;                         // Vale true appena si connette in modo da tenere traccia di eventuali (dis/ri)connesisoni


// Parametri per gestione notifiche e luce
double TEMP_MIN_ALERT = 26 ;
double TEMP_DELTA = 0.5;
double TEMP_STOP = TEMP_MIN_ALERT + TEMP_DELTA ;
double TEMP_MAX_ALERT = 28 ;
int ORA_LUCE_ON = 7;
int ORA_LUCE_OFF = 17;

float intVREF = 1.100;                                                // Variabili per misurare la tensione della batteria

int PIN_LUCE = 3;
int flag_luce = 0;
int PIN_STUFA = 4;
int flag_stufa = 0;
int old_flag_stufa = 0;
char* nome_file_stufa = "f_stufa.txt";
char messaggioHTML[200]; 

// Array dei nomi dei file di configurazione da scaricare
const char* fileNames[] = {"T_min.txt", "T_max.txt", "T_delta.txt", "t_on.txt", "t_off.txt"};          
// Array dei puntatori alle variabili (di tipo void* per gestire tipi diversi)
void* variables[] = {&TEMP_MIN_ALERT, &TEMP_MAX_ALERT, &TEMP_DELTA, &ORA_LUCE_ON, &ORA_LUCE_OFF};
// Array dei tipi delle variabili (1 = double, 2 = int)
int varTypes[] = {1, 1, 1, 2, 2};
int numFiles = sizeof(fileNames) / sizeof(fileNames[0]);




// **********
// Variabili
// **********
//unsigned int millis_ultimo_ciclo;             
unsigned int millis_ultimo_download_file_config;             
unsigned int millis_ultima_rilevazione_wifi;
unsigned int millis_ultima_rilevazione_temp;
unsigned int millis_ultimo_upload_FTP;                                // Soglia di intervallo per upload FTP
unsigned int millis_ultima_notifica_temperatura;                      // Soglia di intervallo per notifiche Telegram

ArduinoLEDMatrix matrix;                                              // Inizializzo la matrice a LED
WiFiClient DLclient;


// SD e files
char filename[20];
char fileNote[20] = "note.txt";
char fileDel[20] = "file_del.txt";
char lineaMessaggio[250];
char nomeFileDaCancellare[10];
char msg[200];
File logfile;
File root;         


// Telegram 

WiFiSSLClient client;
//cppQueue  q_telegram(150, 60, IMPLEMENTATION);          // Istanzio la coda dei mesaggi Telegram -- 60 mesaggi da 150 caratteri ?
AsyncTelegram2 myBot(client);
const char* token  = TELEGRAM_TOKEN;                    // Recupero ID Bot di Telegram
const char* channel = TELEGRAM_CHATID;                  // Recupero ID Chat di Telegram

char* nome_rete;


// FTP variables & c.
char server[40] = FTP_SERVER;
char user[40] = FTP_USER;
char pasw[40] = FTP_PASSWORD;
char fold[40] = FTP_FOLDER;
char outBuf[128];
File fh;
char outCount;
WiFiClient  client_FTP;
WiFiClient  dclient_FTP;


//create a BMx280I2C object using the I2C interface with I2C Address 0x76
BMx280I2C bmx280(I2C_bmx280_ADDRESS);
// uRTCLib rtc;
uRTCLib rtc(I2C_RTC_ADDRESS);


void setup() {
  
  Serial.begin(115200);
  delay(5000);
  // Attendo 5 secondi se non c'è la seriale (ossia se non è attaccato al PC)
  while (!Serial && (millis() < 5000)) {}
  if(Serial){
    serial_avail=true;
    Serial.println("SERIAL OK!!!");
  }
  matrix.begin();   

	URTCLIB_WIRE.begin();
  // Comment out below line once you set the date & time.
  // Following line sets the RTC with an explicit date & time
  // for example to set January 13 2022 at 12:56 you would call:
  // rtc.set(second, minute, hour, dayOfWeek, dayOfMonth, month, year)
  /*
  rtc.set(0, 30, 17, 7, 10, 8, 24);
  messaggioHTML[0]='\0';
  rtc.refresh();
  sprintf(messaggioHTML, "DEBUG: Controllare data ed ora. %02d:%02d:%02d ⏲️ del %02d/%02d/%04d 📅", rtc.hour(),rtc.minute(),rtc.second(), rtc.day(), rtc.month(), (rtc.year()+2000));
  Serial.println(messaggioHTML);
  while(1){};
  */
  // set day of week (1=Sunday, 7=Saturday)      
  
  rtc.refresh();
  if (rtc.year()==0)  {
    Serial.println("RTC initialization failed!");  
    matrix.loadFrame(err_led[0]);  
    while(1){}    
  }  

  //Check/Set SD
  matrix.loadFrame(coda_led[0]);  
  if (!SD.begin(4)) {
    Serial.println("SD initialization failed!");  
    matrix.loadFrame(sd_led[0]);  
    while(1){}
    //NVIC_SystemReset();
  }
  Serial.println("SD initialization done.");  




	//Check/Set termometro
  matrix.loadFrame(coda_led[1]);  
	if (!bmx280.begin())
	{
		Serial.println("begin() failed. check your BMx280 Interface and I2C Address.");
    matrix.loadFrame(coda_led[2]);  
		while (1);
	}  
	bmx280.resetToDefaults();
	bmx280.writeOversamplingPressure(BMx280MI::OSRS_P_x16);
	bmx280.writeOversamplingTemperature(BMx280MI::OSRS_T_x16);


  // Set the Telegram bot properies 
  myBot.setUpdateTime(2000);
  myBot.setTelegramToken(token);



    // Arretro volontariamente l'ultima rilevazione wifi così da farla già al primo ciclo senza aspettare
  millis_ultima_rilevazione_wifi= millis() - intervallo_di_rilevazione_wifi_minuti*1000*60;
     
  // Arretro volontariamente l'ultimo download dei file di configurazione così da farlo già al primo ciclo senza aspettare
  millis_ultimo_download_file_config = millis() - intervallo_download_file_config_minuti*60*1000;

  // Arretro volontariamente l'ultimo upload FTP del file corrente così da farlo già al primo ciclo senza aspettare
  millis_ultimo_upload_FTP = millis() - intervallo_di_upload_FTP_minuti*60*1000;
   
  // Arretro volontariamente l'ultima rilevazione temperatura così da farla già al primo ciclo senza aspettare
  millis_ultima_rilevazione_temp = millis() - intervallo_rilevazione_temp_secondi *1000;

  // Arretro volontariamente l'ultima notifica telegram così da farla già al primo ciclo senza aspettare
  millis_ultima_notifica_temperatura= millis() - intervallo_di_notifica_temperatura_telegram_minuti*60*1000;


  ReadConfigFiles();
  // Sovrascrivi TEMP_STOP: è la temperatura di arresto della stufa, non il delta contenuto nel file
  TEMP_STOP = TEMP_MIN_ALERT + TEMP_DELTA;
  Serial.print("Nuovo TEMP_DELTA : " ); Serial.println(TEMP_DELTA);


  ReadFromFile(nome_file_stufa, 2, &flag_stufa);
  Serial.print("Nuovo flag_stufa : " ); Serial.println(flag_stufa);
  old_flag_stufa = flag_stufa;



}

void loop() {

  // Se non è connesso ma lo era in passato riavvia Arduino
  if (WiFi.status()!=WL_CONNECTED && ConnessoInPassato){ // 0 = Disconnected ?  2 = Looking for ?
      // NOTA: Inutile mandare messaggi via Telegra: tanto è disconnesso.     
      /*
      Serial.println(" ====> RIAVVIO ARDUINO !");      
      if(serial_avail){delay(1000);}
      NVIC_SystemReset();
      */ 
      WiFi.disconnect();
      WiFi.end();
      ConnessoInPassato = false;
      Serial.println(" ====> DISCONNETTO WIFI E END !");      
      if(serial_avail){delay(1000);}           
  }   


  //Check/Set wifi  
  if (WiFi.status()!=WL_CONNECTED){    
    if (millis() - millis_ultima_rilevazione_wifi > intervallo_di_rilevazione_wifi_minuti*1000*60 ){
      matrix.loadFrame(coda_led[3]);  
      Serial.print("Cerco la rete Wifi...");  
      listNetworks();
      // Se la rete risulta connessa non cercarla più
      if (WiFi.status()==WL_CONNECTED){
        Serial.println("... COLLEGATO A WIFI !!");  
        delay(1000);
        matrix.loadFrame(coda_led[4]);          
      }
      millis_ultima_rilevazione_wifi = millis();
    }else{
      //Serial.print("Mancano ");   Serial.print((intervallo_di_rilevazione_wifi_minuti*1000*60  - (millis() - millis_ultima_rilevazione_wifi) )/1000  ); Serial.println(" secondi prima di cercare una rete wifi.");  
      Serial.print("Tempo passato dall'ultima ricerca di una rete WIFI : ");  Serial.print((millis() - millis_ultima_rilevazione_wifi) / 1000 ); Serial.print(" secondi su "); Serial.print(intervallo_di_rilevazione_wifi_minuti *60 );  Serial.println(" secondi");  
    }
  }/*else{
    Serial.println("Già connessa a Wifi");  
  }    */


  // Primo messaggio di benvenuto in Telegram
  //Serial.print("ConnessoInPassato : ");Serial.println(ConnessoInPassato);
  if (!ConnessoInPassato && WiFi.status()==WL_CONNECTED){
    messaggioHTML[0]='\0';
    sprintf(messaggioHTML, "Connesso alla rete 🔗 <b>%s</b> ", nome_rete);
    myBot.sendToChannel(channel, messaggioHTML, true);
    ConnessoInPassato = true;  
  }




  // Scarica i file di configurazione se superata la soglia in minuti dall'ultimo download... 
  if (millis() - millis_ultimo_download_file_config > intervallo_download_file_config_minuti *60  *1000 )
  { 
    if (WiFi.status()==WL_CONNECTED){
      Serial.println("INIZIO SCARICAMENTO FILE DI CONFIGURAZIONE");
      int n_file_da_aggiornare = numFiles;
      int n_file_aggiornati =0;

      // Buffer per header e body
      char header[HEADER_SIZE] = {0};
      char body[BODY_SIZE] = {0};

      for (int i = 0; i < numFiles; i++) {
        Serial.print("Scaricando file: "); Serial.println(fileNames[i]);
        bool success = DownloadFile(fileNames[i], header, body);
        if (success && strlen(body) > 0) {
          n_file_aggiornati +=1;
          Serial.print("Contenuto del file "); Serial.print(fileNames[i]); Serial.print(":");Serial.println(body);

          // Assegna il contenuto del body alla variabile appropriata
          if (varTypes[i] == 1) { // double
            *(double*)variables[i] = atof(body);
          } else if (varTypes[i] == 2) { // int
            *(int*)variables[i] = atoi(body);
          }
        } else {
          Serial.print("Errore nel download del file: "); Serial.println(fileNames[i]);
        }
        // Pulizia dei buffer
        memset(header, 0, sizeof(header));
        memset(body, 0, sizeof(body));
      }

      // Stampa i valori per verifica
      Serial.print("TEMP_MIN_ALERT: "); Serial.println(TEMP_MIN_ALERT);
      Serial.print("TEMP_MAX_ALERT: "); Serial.println(TEMP_MAX_ALERT);
      Serial.print("TEMP_DELTA: "); Serial.println(TEMP_DELTA);
      Serial.print("ORA_LUCE_ON: "); Serial.println(ORA_LUCE_ON);
      Serial.print("ORA_LUCE_OFF: "); Serial.println(ORA_LUCE_OFF);

      TEMP_STOP = TEMP_MIN_ALERT + TEMP_DELTA;
      // Solo se ho aggiornato tutti i files allora aggiorna il tempo  
      if (n_file_aggiornati==n_file_da_aggiornare){
        // Sovrascrivi TEMP_STOP: è la temperatura di arresto della stufa, non il delta contenuto nel file
        Serial.print("Nuovo TEMP_STOP : " ); Serial.println(TEMP_STOP);
        
        messaggioHTML[0]='\0';
        rtc.refresh();
        sprintf(messaggioHTML, "Scaricati i file di configurazione ⚙️ alle ore %02d:%02d:%02d ⏲️ del %02d/%02d/%d 📅", rtc.hour(),rtc.minute(),rtc.second(), rtc.day(), rtc.month(), (rtc.year()+2000));
        myBot.sendToChannel(channel, messaggioHTML, true);

        millis_ultimo_download_file_config = millis();            
      }else{
         Serial.println("NON AGGIORNO IL millis() PER IL DOWNLOAD DEI FILE DI CONFIGURAZIONE");
      }
    }
  }else{
    Serial.print("Tempo passato dall'ultimo download : ");  Serial.print((millis() - millis_ultimo_download_file_config) / 1000 ); Serial.print(" secondi su "); Serial.print(intervallo_download_file_config_minuti *60 );  Serial.println(" secondi");  
  }








  // Fa la misura della temperatura se superata la soglia in minuti dall'ultima misura...   
  if (millis() - millis_ultima_rilevazione_temp > intervallo_rilevazione_temp_secondi *1000 )
  { 
    //start a measurement
    matrix.loadFrame(coda_led[5]);  
    if (!bmx280.measure())
    {    
      Serial.println("could not start measurement, is a measurement already running?");
      return;
    }
    //wait for the measurement to finish
    do
    {
      delay(50);
    } while (!bmx280.hasValue());         
    matrix.loadFrame(coda_led[6]);  


    // Costruisci il nome del file: dopo mezzanotte cambia
    rtc.refresh();
    filename[0] = '\0';
    sprintf(filename, "D_%02d%02d%d.TXT", rtc.day() ,rtc.month(),rtc.year());
    matrix.loadFrame(coda_led[7]);  


    // ******** Gestisci temperatura e luce ********
    // Flag luce
    if (rtc.hour()>=ORA_LUCE_ON  && rtc.hour()< ORA_LUCE_OFF){
      digitalWrite(PIN_LUCE,HIGH);       //Luce sul PIN 3
      flag_luce = 1;
    }else{
      digitalWrite(PIN_LUCE,LOW);     //Luce sul PIN 3
      flag_luce = 0;  
    }  
    // Flag stufa
    if(bmx280.getTemperature() <= TEMP_MIN_ALERT ){    
      digitalWrite(PIN_STUFA,HIGH);     //Stufa sul PIN 4
      flag_stufa = 1;
    }
    if(bmx280.getTemperature() >= TEMP_STOP ){
      digitalWrite(PIN_STUFA,LOW);      //Stufa sul PIN 4
      flag_stufa = 0;  
    }
    // Salva il file con il flag se è cambiato
    if (flag_stufa!= old_flag_stufa){    
      //Serial.print("Vecchio flag_stufa : " ); Serial.println(old_flag_stufa);
      //Serial.print("Nuovo flag_stufa : " ); Serial.println(flag_stufa);    
      // Cancello il file vecchio se esiste
      if (SD.exists(nome_file_stufa)) {
        SD.remove(nome_file_stufa);
      }
      File file_stufa = SD.open(nome_file_stufa, FILE_WRITE);
      if (file_stufa) {
        file_stufa.println(flag_stufa);
        file_stufa.close();      
      } else {
        Serial.print("Errore apertura file: ");  Serial.println(nome_file_stufa);
      }  
      // Verifico la scrittura su file
      //ReadFromFile(nome_file_stufa, 2, &flag_stufa);
      //Serial.print(" flag_stufa letto da file: " ); Serial.println(flag_stufa);
    }
    if (WiFi.status()==WL_CONNECTED){ 
      messaggioHTML[0]='\0';
      rtc.refresh();
      if (old_flag_stufa==0 && flag_stufa==1){
        sprintf(messaggioHTML, "La stufa si accende 🔥 alle ore %02d:%02d:%02d ⏲️ del %02d/%02d/%d ", rtc.hour(),rtc.minute(),rtc.second(), rtc.day(), rtc.month(), (rtc.year()+2000));
      }
      if (old_flag_stufa==1 && flag_stufa==0){
        sprintf(messaggioHTML, "La stufa si spegne 🪵 alle ore %02d:%02d:%02d ⏲️ del %02d/%02d/%d ", rtc.hour(),rtc.minute(),rtc.second(), rtc.day(), rtc.month(), (rtc.year()+2000));  
      }    
      if(messaggioHTML[0]!='\0'){
        Serial.print("Messaggio telegram stufa: "); Serial.println(messaggioHTML);
        if (WiFi.status()==WL_CONNECTED){   // se sei connesso 
          myBot.sendToChannel(channel, messaggioHTML, true);  // mandala subito
        }else{
          File NoteFile = SD.open(fileNote, FILE_WRITE);   // altrimenti scrivla nel file "note.txt"
          if (NoteFile) {
            NoteFile.println(messaggioHTML);
            NoteFile.close();
          }
        }
      }



      
    }  
    old_flag_stufa = flag_stufa;



    // Costruisci la riga di log e scrivila
    rtc.refresh();
    msg[0] = '\0';
    
    sprintf(msg, "%d;%02d;%02d;%02d;%02d;%02d;%.2f;%.2f;%d;%.2f;%.2f;%.2f;%d;%d", (rtc.year()+2000) ,rtc.month(),rtc.day(),rtc.hour(),rtc.minute(),rtc.second(),bmx280.getTemperature(),bmx280.getPressure64(),readVcc(),TEMP_MIN_ALERT,TEMP_STOP,TEMP_MAX_ALERT,flag_luce,flag_stufa  );
    // Scrivo solo se non contiene 'nan'
    if (strstr(msg, "nan") == nullptr){
      logfile = SD.open(filename, FILE_WRITE);
      if (logfile){
        logfile.println(F(msg));
        logfile.close();
      }
      matrix.loadFrame(coda_led[8]);  
    }else{
      matrix.loadFrame(coda_led[10]);  
    }


    // DEBUG: Check sui valori 
    
    Serial.print("     "); Serial.print("Nome file : ");Serial.print(filename);
    Serial.print("     ");Serial.print(' ');  Serial.print(rtc.hour());	 Serial.print(':'); Serial.print(rtc.minute()); Serial.print(':'); Serial.print(rtc.second());
    Serial.print("     ");Serial.print("Riga log : ");Serial.print(msg);
    //Serial.print("     ");Serial.print("Pressure:"); Serial.print(bmx280.getPressure64());Serial.print(" Temperature: ");Serial.println(bmx280.getTemperature());
    //Serial.print("     ");Serial.print("WiFi Status: ");  Serial.println(WiFi.status());
    rtc.refresh();
    Serial.print("     ");
    messaggioHTML[0]='\0';    
    sprintf(messaggioHTML, "Sono le ore %02d:%02d:%02d del %02d/%02d/%04d", TEMP_MIN_ALERT, rtc.hour(),rtc.minute(),rtc.second(), rtc.day(), rtc.month(), (rtc.year()+2000), bmx280.getTemperature());            
    Serial.print(messaggioHTML);    
    //Serial.print("     ");Serial.print(" - Temp RTC: ");  Serial.print(rtc.temp()  / 100); 
    Serial.println("");  
    if(serial_avail){delay(2000);}

    //millis_ultimo_ciclo = millis(); 

  

    // Calcola quanto tempo è passato dall'ultima rilevazione e aspetta la differenza
    /*Serial.println(intervallo_rilevazione_temp_secondi*1000);
    Serial.println(millis() - millis_ultima_rilevazione_temp);
    Serial.println((millis() - millis_ultima_rilevazione_temp) - intervallo_rilevazione_temp_secondi*1000 );
    Serial.println("Ora fa la misura");
    while(1){};  
    */

    millis_ultima_rilevazione_temp = millis();   
  }else{
    Serial.print("Tempo passato dall'ultima rilevazione : ");  Serial.print((millis() - millis_ultima_rilevazione_temp) / 1000 ); Serial.print(" secondi su "); Serial.print(intervallo_rilevazione_temp_secondi );  Serial.println(" secondi");  
    //delay(1000);
  }







  // ******** Gestisci CREAZIONE di notifiche fuori soglia ********
  if (millis() - millis_ultima_notifica_temperatura > intervallo_di_notifica_temperatura_telegram_minuti *60  *1000 )
  { 
    // ... e se la temperatura rilevata è esterna alle soglie min e max
    rtc.refresh();
    messaggioHTML[0]='\0';
    if (bmx280.getTemperature()< TEMP_MIN_ALERT){        
      sprintf(messaggioHTML, "La temperatura 🌡‍️ è scesa 🥶 sotto la soglia di %.02f gradi alle ore %02d:%02d:%02d 🕰 del %02d/%02d/%d ed è pari a <b>%.02f</b> gradi", TEMP_MIN_ALERT, rtc.hour(),rtc.minute(),rtc.second(), rtc.day(), rtc.month(), (rtc.year()+2000), bmx280.getTemperature());        
    }
    if (bmx280.getTemperature()> TEMP_MAX_ALERT){     
      sprintf(messaggioHTML, "La temperatura 🌡‍️ è salita 🥵 sopra la soglia di %.02f gradi alle ore %02d:%02d:%02d 🕰 del %02d/%02d/%d ed è pari a <b>%.02f</b> gradi", TEMP_MAX_ALERT, rtc.hour(),rtc.minute(),rtc.second(), rtc.day(), rtc.month(), (rtc.year()+2000), bmx280.getTemperature());                   
    }
    if (messaggioHTML[0]!='\0'){   // se c'è una notifica        
      if (WiFi.status()==WL_CONNECTED){   // se sei connesso 
        myBot.sendToChannel(channel, messaggioHTML, true);  // mandala subito
      }else{
        File NoteFile = SD.open(fileNote, FILE_WRITE);   // altrimenti scrivla nel file "note.txt"
        if (NoteFile) {
          NoteFile.println(messaggioHTML);
          NoteFile.close();
          Serial.print("Messaggio ");            Serial.println(messaggioHTML);            
          Serial.println("Scritto nel file");            
        } else {
          Serial.println("Errore nell'apertura del file delle notifiche.");            
        }
        if(serial_avail){delay(2000);}
      }  
      millis_ultima_notifica_temperatura = millis();             
    }

  }else{
    Serial.print("Tempo passato dall'ultima notifica della temperatura fuori soglia : ");  Serial.print((millis() - millis_ultima_notifica_temperatura) / 1000 ); Serial.print(" secondi su "); Serial.print(intervallo_di_notifica_temperatura_telegram_minuti*60 );  Serial.println(" secondi");  
  }











  // Fa upload del file se superata la soglia in minuti dall'ultimo upload... 
  if (millis() - millis_ultimo_upload_FTP > intervallo_di_upload_FTP_minuti * 60 *1000 )
  { 
    if (WiFi.status()==WL_CONNECTED){
      matrix.loadFrame(coda_led[9]);  
      if (SD.exists(filename)) {

        // Fai FTP del file del giorno corrente
        char annoStr[3]; // 2 caratteri + 1 per il terminatore
        char meseStr[3]; // 2 caratteri + 1 per il terminatore

        // Copia i caratteri da 6 a 8 (24)
        strncpy(annoStr, filename + 6, 2); // 6 è l'indice del 6° carattere
        annoStr[2] = '\0'; // Terminatore di stringa

        // Copia i caratteri da 4 a 6 (07)
        strncpy(meseStr, filename + 4, 2); // 4 è l'indice del 4° carattere
        meseStr[2] = '\0'; // Terminatore di stringa

        // Converti le sottostringhe in int
        int anno_da_nomefile = atoi(annoStr);
        int mese_da_nomefile = atoi(meseStr);

        // Aggiungi 2000 all'anno per ottenere 2024
        anno_da_nomefile += 2000;     

        matrix.loadFrame(ftp_led[0]);  
        byte Upload_OK = doFTP(filename, anno_da_nomefile, mese_da_nomefile );
        matrix.loadFrame(ftp_led[1]);          
        if (Upload_OK){
          // Notifica Telegram per FTP file del giorno corrente
          rtc.refresh();
          messaggioHTML[0]='\0'; 
          sprintf(messaggioHTML, "Il file <b>%s</b> è stato caricato 🆙 alle ore %02d:%02d:%02d del %02d/%02d/%d", filename , rtc.hour(),rtc.minute(),rtc.second(), rtc.day(), rtc.month(), (rtc.year()+2000));             
          Serial.println("Messaggio telegram: ");     
          Serial.println(messaggioHTML);        
          myBot.sendToChannel(channel, messaggioHTML, true);     
          millis_ultimo_upload_FTP = millis(); 
        }
      }else{
       Serial.print("Tempo per fare l'upload FTP è passato, sei connesso ma il file '");   Serial.print(filename);Serial.println("' non esiste!");
      }
    }else{
      Serial.println("Tempo per fare l'upload FTP è passato ma non sei connesso!"); 
    }
  }else{
    Serial.print("Tempo passato dall'ultimo upload FTP : "); Serial.print((millis() - millis_ultimo_upload_FTP) / 1000 );  Serial.print(" secondi su "); Serial.print(intervallo_di_upload_FTP_minuti *60 );  Serial.println(" secondi");  
  }




  // Ultima cosa da fare sempre: se esiste il file di notifiche 'note.txt' e sono connesso invio un messaggio alla volta
    if (SD.exists(fileNote)) {
      if(WiFi.status()==WL_CONNECTED){
        File file = SD.open(fileNote);    
        while (file.available()) {
            int index = 0;
            // Leggi la riga corrente
            while (file.available() && index < sizeof(lineaMessaggio) - 1) {
                char c = file.read();
                if (c == '\n') {
                    break;
                }
                lineaMessaggio[index++] = c;
            }
            lineaMessaggio[index] = '\0';  // Termina la stringa

            // Stampa la riga letta            
            myBot.sendToChannel(channel, lineaMessaggio, true);
            delay(100);

            //Serial.println(lineaMessaggio);
            //if(serial_avail){delay(3000);}
        }
        file.close();  // Chiudi il file dopo aver terminato la lettura
        SD.remove(fileNote);  // Rimuovi il file suponendo che abbia mandato tutte le notifiche indietro
      }
    }









} 







// *********************************************
//      UTILITIES FUNCTIONS
// *********************************************




bool DownloadFile(const char* FileName, char* header, char* body) {
  WiFiClient DLclient;  
  char msg_file[200];
  memset(header, 0, HEADER_SIZE);
  memset(body, 0, BODY_SIZE);
  
  if (DLclient.connect(WEB_SERVER, 80)) {
    char get_req[200];
    sprintf(get_req, "GET /termometro/config/%s HTTP/1.1", FileName);
    DLclient.println(get_req);
    DLclient.println("Host: <mio_sito>.altervista.org");
    DLclient.println("Connection: close");
    DLclient.println("");

    unsigned long t1 = millis();
    while (DLclient.available() == 0) {
      if ((millis() - t1) > 15000) {
        Serial.println("Timeout");
        DLclient.stop();
        return false;
      }
    }

    // Ricezione dati
    char line[256];
    bool headerComplete = false;

    while (DLclient.connected() || DLclient.available()) { 
      memset(line, 0, sizeof(line));
      DLclient.readBytesUntil('\n', line, 255);
      line[strcspn(line, "\r")] = 0;  // Rimuove i caratteri di ritorno a capo

      /*
      
        msg_file[0] = '\0';
        sprintf(msg_file, "==> Linea letta : %s", line);
        Serial.println(msg_file);
      
      */

      if (!headerComplete) {
        if (strlen(line) == 0) {
          headerComplete = true;
        } else {
          strncat(header, line, HEADER_SIZE - strlen(header) - 1);
          strncat(header, "\n", HEADER_SIZE - strlen(header) - 1);
        }
      } else {
        strncat(body, line, BODY_SIZE - strlen(body) - 1);
        strncat(body, "\n", BODY_SIZE - strlen(body) - 1);
      }


    }
    DLclient.stop();

    // Cancello il file vecchio se esiste
    if (SD.exists(FileName)) {
      SD.remove(FileName);
      msg_file[0] = '\0';
      if (!SD.exists(FileName)) {
        sprintf(msg_file, "File vecchio %s rimosso con successo. ", FileName);
      } else {
        sprintf(msg_file, "File vecchio %s NON rimosso !! ", FileName);
      }
      Serial.print(msg_file);
    }

    File DLfile = SD.open(FileName, FILE_WRITE);
    if (DLfile) {
      DLfile.println(body);
      DLfile.close();
    } else {
      Serial.println("Errore nell'apertura del file per la scrittura.");
      return false;
    }

    msg_file[0] = '\0';
    if (SD.exists(FileName)) {
      sprintf(msg_file, "Il file %s è stato (ri)creato con successo", FileName);
    } else {
      sprintf(msg_file, "Il file %s NON è stato creato", FileName);
      return false;
    }
    Serial.println(msg_file);
    return true;
  } else {
    Serial.println("Errore nel download del file - NON Connesso");
    return false;
  }
}


void ReadConfigFiles(){
  //const char* FileName, char* header, char* body
  int numFiles = sizeof(fileNames) / sizeof(fileNames[0]);

  for (int i = 0; i < numFiles; i++) {
      ReadFromFile(fileNames[i], varTypes[i], variables[i]);
  }

  // Stampa i valori per verifica
  
   Serial.println("*** VALORI LETTI DAI FILE DI CONFIGURAZIONE ****");
   Serial.print("TEMP_MIN_ALERT: "); Serial.print(TEMP_MIN_ALERT); Serial.print(" ");
   Serial.print("TEMP_MAX_ALERT: "); Serial.print(TEMP_MAX_ALERT);Serial.print(" ");
   Serial.print("TEMP_STOP: "); Serial.print(TEMP_STOP);Serial.print(" ");
   Serial.print("ORA_LUCE_ON: "); Serial.print(ORA_LUCE_ON);Serial.print(" ");
   Serial.print("ORA_LUCE_OFF: "); Serial.print(ORA_LUCE_OFF);Serial.print(" ");
   Serial.println("");
  
  
}


bool ReadFromFile(const char* FileName, int varType, void* variable) {
    if (SD.exists(FileName)) {
        File file = SD.open(FileName);
        if (file) {
            // Assicurati che il buffer sia abbastanza grande per contenere il contenuto del file
            char buffer[16];  // Modifica la dimensione in base alle tue necessità
            int index = 0;

            // Leggi il file fino al carattere di nuova linea o fine del file
            while (file.available() && index < sizeof(buffer) - 1) {
                char c = file.read();
                if (c == '\n') {
                    break;
                }
                buffer[index++] = c;
            }
            buffer[index] = '\0';  // Termina la stringa
            file.close();

            // Assegna il contenuto del file alla variabile appropriata
            if (varType == 1) {
                *(double*)variable = atof(buffer);
            } else if (varType == 2) {
                *(int*)variable = atoi(buffer);
            } else {
                return false;
            }

            return true;
        } else {
            
             Serial.print("Errore nell'apertura del file: ");
             Serial.println(FileName);
            
            return false;
        }
    } else {
      
        Serial.print("Il file ");
        Serial.print(FileName);
        Serial.println(" non esiste.");
      
      return false;
    }
}




void listNetworks() {
  // scan for nearby networks:
  Serial.println("** Scan Networks **");
  int numSsid = WiFi.scanNetworks();
  if (numSsid != -1) {
    // print the list of networks seen:
    Serial.print("number of available networks:");
    Serial.println(numSsid);
    

    // print the network number and name for each network found:
    for (int thisNet = 0; thisNet < numSsid; thisNet++) {
    
      Serial.print(thisNet); Serial.print(") "); Serial.print(WiFi.SSID(thisNet)); Serial.print(" Signal: "); Serial.print(WiFi.RSSI(thisNet)); Serial.print (" dBm ");

      if (strcmp(WiFi.SSID(thisNet), SECRET_SSID1) == 0){        
        Serial.print (" **** => TROVATA : "); Serial.println (SECRET_SSID1);
        char pass[] = SECRET_PASS1;   
        if(connetti_rete(SECRET_SSID1,pass)){
          thisNet = numSsid;
        }
      }  
      else if (strcmp(WiFi.SSID(thisNet), SECRET_SSID2) == 0){    
        Serial.print (" **** => TROVATA : ");Serial.println (SECRET_SSID2);
        char pass[] = SECRET_PASS2;
        if(connetti_rete(SECRET_SSID2,pass)){
          thisNet = numSsid;
        }
      }  
      else if (strcmp(WiFi.SSID(thisNet), SECRET_SSID3) == 0){    
        Serial.print (" **** => TROVATA : ");Serial.println (SECRET_SSID3);
        char pass[] = SECRET_PASS3;
        if(connetti_rete(SECRET_SSID3,pass)){
          thisNet = numSsid;
        }
      }   
      else if (strcmp(WiFi.SSID(thisNet), SECRET_SSID4) == 0){    
        Serial.print (" **** => TROVATA : ");Serial.println (SECRET_SSID4);
        char pass[] = SECRET_PASS4;
        if(connetti_rete(SECRET_SSID4,pass)){
          thisNet = numSsid;
        }
      }   
      else if (strcmp(WiFi.SSID(thisNet), SECRET_SSID5) == 0){    
        Serial.print (" **** => TROVATA : ");Serial.println (SECRET_SSID5);
        char pass[] = SECRET_PASS5;
        if(connetti_rete(SECRET_SSID5,pass)){
          thisNet = numSsid;
        }
      } 
    }   
  }
}


bool connetti_rete(char NetName[], char NetPwd[]){
  bool res = false;
  unsigned int SOGLIA_MS_RICERCA_RETE = 200;
  Serial.print("Try to connect to '");  Serial.print(NetName);  Serial.println("' ...");
  WiFi.begin(NetName,NetPwd);
  
  unsigned int t1 = millis();  
  while (WiFi.status()!=WL_CONNECTED){
    delay(50);    
    Serial.print(".");
    // Se è passato troppo tempo smetti di cercare questa rete  
    if(millis() - t1 > SOGLIA_MS_RICERCA_RETE && WiFi.status()!=WL_CONNECTED ){
      Serial.println("Esco per troppo tempo passato");
      return false;
    }    
  }  


  if (WiFi.status()==WL_CONNECTED){
    Serial.println("==> CONNESSA !!");
    nome_rete = NetName;
    res = true;
  }
  return res;
}


long readVcc()
{ // function to read actual supply voltage Vcc (in mV) of Arduino - adapted to also work with new UNO R4
  long result;
  float Vcc = analogReference();        // analogReference() reads Vcc, based on internal reference, and returns value as a float
  result = Vcc * intVREF * 1000;        //  intVREF * 1000;   // result is corrected for incorrect internal reference (fixed factor) and converted to mV
  return result;                        // long result (Vcc in mV) is returned as a result of readVccUnoR4 function
}




byte doFTP(String filename, int anno_da_nomefile,int mese_da_nomefile)
{
  fh = SD.open(filename,FILE_READ);
  if(!fh)
  {
    Serial.println(F("doFTP: SD open fail"));
    return 0;    
  }
  Serial.println(F("doFTP: SD opened"));
  if (client_FTP.connect(server,21)) {
    Serial.println(F("doFTP: Command connected"));
  }
  else {
    fh.close();
    Serial.println(F("doFTP: Command connection failed"));
    return 0;
  }
  if(!eRcv()) return 0;
    client_FTP.print(F("USER "));
    client_FTP.println((String)user);
  if(!eRcv()) return 0;
   client_FTP.print(F("PASS "));
   client_FTP.println((String)pasw);
  if(!eRcv()) return 0;
  client_FTP.println(F("SYST"));
  if(!eRcv()) return 0;
  client_FTP.println(F("Type I"));
  if(!eRcv()) return 0;
  client_FTP.println(F("PASV"));
  if(!eRcv()) return 0;
  char *tStr = strtok(outBuf,"(,");
  int array_pasv[6];
  for ( int i = 0; i < 6; i++) {
    tStr = strtok(NULL,"(,");
    array_pasv[i] = atoi(tStr);
    if(tStr == NULL)
    {
      Serial.println(F("doFTP: Bad PASV Answer"));   
    }
  }
  client_FTP.println(F("PWD"));
  if(!eRcv()) return 0;
  client_FTP.print(F("CWD "));
  client_FTP.println(fold);  
  if(!eRcv()) return 0;  
  client_FTP.print(F("CWD "));
  client_FTP.println(anno_da_nomefile);
  if(!eRcv()) return 0;  
  client_FTP.print(F("CWD "));
  client_FTP.println(mese_da_nomefile);
  if(!eRcv()) return 0;    
  unsigned int hiPort,loPort;
  hiPort = array_pasv[4] << 8;
  loPort = array_pasv[5] & 255;
  Serial.print(F("Data port: "));
  hiPort = hiPort | loPort;
  Serial.println(hiPort);
  if (dclient_FTP.connect(server,hiPort)) {
    Serial.println(F("doFTP: Data connected"));
  }
  else {
    Serial.println(F("doFTP: Data connection failed"));
    client_FTP.stop();
    fh.close();
    return 0;
  }
  client_FTP.print(F("STOR "));
  client_FTP.println(filename);
  if(!eRcv())
  {
    dclient_FTP.stop();
    return 0;
  }
  Serial.println(F("doFTP: Writing"));
  byte clientBuf[64];
  int clientCount = 0;
  while(fh.available())
  {
    clientBuf[clientCount] = fh.read();
    clientCount++;
    if(clientCount > 63)
    {
      dclient_FTP.write(clientBuf,64);
      clientCount = 0;
    }
  }
  if(clientCount > 0) dclient_FTP.write(clientBuf,clientCount);
  dclient_FTP.stop();
  Serial.println(F("doFTP: Data disconnected"));
  if(!eRcv()) return 0;
  client_FTP.println(F("QUIT"));
  if(!eRcv()) return 0;
  client_FTP.stop();
  Serial.println(F("doFTP: Command disconnected"));
  fh.close();
  Serial.println(F("doFTP: SD closed"));
  return 1;
}

byte eRcv()
{
  byte respCode;
  byte thisByte;
  while(!client_FTP.available()) delay(1);
  respCode = client_FTP.peek();
  outCount = 0;
  while(client_FTP.available())
 {  
   thisByte = client_FTP.read();    
   Serial.write(thisByte);
    if(outCount < 127)
    {
      outBuf[outCount] = thisByte;
      outCount++;      
      outBuf[outCount] = 0;
    }
  }
  if(respCode >= '4')
  {
    efail();
    return 0;  
  }
  return 1;
}


void efail()
{
  byte thisByte = 0;
  client_FTP.println(F("QUIT"));
  while(!client_FTP.available()) delay(1);
  while(client_FTP.available())
  {  
    thisByte = client_FTP.read();    
    Serial.write(thisByte);
  }
  client_FTP.stop();
  Serial.println(F("Command disconnected"));
  fh.close();
  Serial.println(F("SD closed"));
}

Nei test "a muro" hai provato alimentatori diversi?

1 Like

Sì questi più un altro

Ho provato anche con il connettore nero e un trasformatore col positivo al centro come diceva @gpb01 qui ma il risultato è lo stesso: ho un comportamento veramente strano.

Qualcuno ha qualche idea?
:frowning:

... il PC normalmente ha una connessione a "terra", gli alimentatori che illustri NO ... potrebbero essere disturbi sulla rete di alimentazione. :roll_eyes:

Guglielmo

Vediamo se ho capito. Scusami ma non sono molto bravo.
Secondo te potrebbe essere perché manca la massa a terra negli alimentatori che uso. Il filo giallo e verde che sta in mezzo.
Giusto?

Ma essitono trasformatori da muro con la messa a terra? Ho cercato un pò ma trovo solo fase/neutro non fase/neutro/terra

Questa è la prima differenza che mi viene in mente tra le due alimentazioni ... :roll_eyes:

Guglielmo

1 Like

La seconda differenza, ma non sono un elettronico perciò non so se influisce, è che quelli NON sono alimentatori veri e propri ma sono pensati per caricare i cellulari.

1 Like

Sta sera provo con un alimtatore da 12V e 1A sempre con positivo al centro che era nella scatola del connettore di un Box di un hard disk esterno per PC.
Anche quello non ha la terra, però 'esco' dal perimetro dell'alimentazione per smartphone/tablet come hai suggerito.
Vi faccio sapere nelle prossime ore.

Puoi comunque aggiungere un collegamento a terra..

Nota che per le letture di millis() servono variabili unsigned long, ovvero uint32_t!

Grazie mille @Datman per il suggerimento. Ma non so come fare ad aggiungere la terra...
Sapresti darmi delle indicazioni o un link che me lo spieghi?

Poi controllo il codice e se non è così cambierò il tipo del millis().
Mi puoi spiegare perché influisce? Hai visto il codice e non l'ho fatto oppure c'è qualche altro motivo.

Scusa se le domande possono essere un po' da ignorantone ma sto imparando.

//unsigned int millis_ultimo_ciclo;             
unsigned int millis_ultimo_download_file_config;             
unsigned int millis_ultima_rilevazione_wifi;
unsigned int millis_ultima_rilevazione_temp;
unsigned int millis_ultimo_upload_FTP;                                // Soglia di intervallo per upload FTP
unsigned int millis_ultima_notifica_temperatura;    

Per la terra, puoi fare la prova con un piccolo apparecchio con spina a tre poli, collegando il negativo di Arduino al metallo dell'apparecchio.

Mmmm ... nota che lui è su UNO R4, ovvero su una MCU a 32 bit dove, se ben ricordo, gli "int" sono proprio a 32 bit e quindi, casualmente, la cosa funziona anche così (se era su UNO R3, dove 'int' è a 16 bit, NO).


@skelos: il problema nasce dal fatto che una variabile di tipo 'int ha dimensioni differenti a seconda della piattaforma che usi. Un 'int' su Arduino UNO R3 (ATmega328P, MCU a 8 bit) occupa 16 bit, lo stesso 'int' utilizzato su Arduino UNO r4 (Renesas RA4M1, MCU a 32 bit) occupa 32 bit.
Per evitare questi problemi di variazione della lunghezza di variabile, in funzione della piattaforma, si possono definire i 'tipi variabile' che si trovano in <stdint.h> che, normalmente, viene sempre automaticamente incluso (se da errore, occorre includerlo a mano con una #include) ...
... tali tipi definiscono in modo univoco e "parlante" (ovvero si capisce già leggendo il tipo cosa sono) le varie variabili:

uint8_t  : un byte da 8 bit non segnato (0..255)
int8_t   : un byte da 8 bit con segno (-128..+127)
uint16_t : una variabile da 16 bit non segnata (0..65535)
int16_t  : una variabile da 16 bit con segno (-32768..+32767)
uint32_t : una variabile da 32 bit non segnata (0..4294967295)
int32_t  : una variabile da 32 bit con segno (-2147483648..2147483647)
... e così via

Spero di averti chiarito un po' la situazione :wink:

Guglielmo

1 Like

Sapresti indicarmi il tipo di apparecchio di cui stai parlando? Un link, un codice o qualcosa di simile?

Un apparecchio che hai in casa che disponga di una spina a tre poli.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.