Ciao a tutti,
su consiglio di molti topic di questo forum, sto provando a non utilizzare String a favore della libreria SafeString.
Non ho però capito un dettaglio: se io ho delle variabili numeriche (es. int o float) come devo fare per concaternarle in una SafeString unica?
Scusa .. ma hai visto che in area "Software" c'è una discussione dedicata alla SafeString? Perché non porre le domande li invece che creare una nuova discussione?
E comunque ... come indicato in quella discussione, QUI si trova un ampio tutorial ... buono studio
Credo che non scriverò più in questo forum, non capisco il motivo di dare sempre questo tipo di risposte.
Se scrivo è perchè non sono riuscito a reperire una risposta.
Non tutti sono programmatori, e spesso qualcuno può incontrare difficoltà con l'inglese.
Non ho scritto nel topic da te indicato perchè spesso si dice di non scrivere sotto topic vecchi ma di aprirne di nuovi, inoltre in quel topic è scritto che è stato creato solo con lo scopo di informare di questa alternativa data dalla libreria SafeString e non ho voluto sporcarlo con questa mia domanda.
Il tutorial l'ho scorso e non sono riuscito a trovare quello che cerco, altrimenti ovviamente non avrei perso tempo per chiedere.
Se anche ci fosse la risposta lì e non sono riuscito a trovarla, visto che credo che la risposta sia semplice (spero), non capisco il senso di dire a un utente di leggere 100 pagine invece di spiegare come si dovrebbe fare in poche righe.
Vero, perché spesso l'argomento cambia, ma nel tuo caso, l'argomento era lo stesso e quindi magari la domanda poteva starci
Lo abbiamo detto e ripetuto spesso ... qui NON diamo la "pappa fatta" ... è anche ben descritto al punto 16.13 del REGOLAMENTO ... indichiamo dove e come trovare la risposta, ma è poi l'utente che si deve impegnare per trovarla ...
Hai provato a guardare anche tra gli esempi della libreria?
Con la classe String che "operatori" useresti? La stessa cosa con la SafeString ...
Ci sono dei limiti di lunghezza in questi nuovi oggetti SafeString?
A cosa può essere dovuto questo errore?
Inoltre ho un'altra curiosità.
Quando si esegue il codice che riporto di seguito, senza l'utilizzo della libreria SafeString, si è esposti al problema che può bloccare l'esecuzione del codice o si tratta di una semplice conversione che non crea alcun fastidio all'esecuzione?
Stai usando un ESP32 che ti mette a disposizione 520kB di SRAM e ti fai problemi nell'usare la classe String???
Che poi se si usa come si deve, problemi non ce ne sono manco con le MCU piccolette tipo quella della Arduino Uno a dirla tutta.
Io continuo ad essere dell'idea che questa storia che è necessario evitare la classe String a tutti i costi fa più danni che benefici...
Per me è un argomento nuovo, di cui non ero a conoscenza.
Utilizzo una variabile String di circa 220 caratteri per salvare un url che poi utilizzo per caricare dei dati su un database.
Questa operazione viene eseguita ogni dieci minuti.
Riscontro che esp32 ogni circa 2 3 giorni si blocca e deve essere riavviato.
L'unico motivo che ho trovato possibile mi sembra essere questo quindi stavo tentando di non usare String e vedere se il problema si ripete.
Trovo anche io strano sia questa la motivazione, prima utilizzavo un esp8266 e funzionava per mesi senza problemi e avevo lo stesso url ed eseguivo l'operazione identica ogni 10 minuti.
Non riesco però a trovare altri motivi che possano generare questo blocco.
Si tratta di una stazione meteo, che ogni minuto legge i dati dai sensori, e ogni 10 letture fa le medie e invia i dati a una pagina web per il caricamento nel database.
#include <Adafruit_Sensor.h> //per gestire il sensore BME280
#include <Adafruit_BME280.h> //per gestire il sensore BME280
#include <WiFiClientSecure.h> //per gestire la connessione alla rete Wifi e al client
#include <WiFi.h> //per gestire la connessione wifi
#include <Wire.h> //per gestire I2C
//dati per la connessione alla rete Wifi
const char* SSID = "xxx";
const char* PASSWORD = "xxx";
//dati per la connessione
const char* server = "xxx";
const uint16_t port = 443;
//dati intervallo lettura sensori
unsigned long tempo_start_lettura_sensori;
unsigned long intervallo_lettura_sensori = 60000; //effettuiamo una lettura dei sensori ogni 60 secondi
//dati sensore BME280
Adafruit_BME280 sensore_temp_umid_press_BME280;
//dati sensore fotoresistenza
const int pinFotoresistenza = 32;
//dati anemometro
const float pigreco = 3.141593;
const float raggio = 0.06; //raggio dell'anemometro in metri
const int pinAnemometro = 27;
int stato_reed_anemometro = 0;
int stato_reed_old_anemometro = 0; //variabile per evitare doppie pulsazioni
int num_pulsazioni = 0; //numero di pulsazioni (una per giro, c'è un solo magnete)
unsigned long int tempo_start_anemometro = 0; //memorizza i millisecondi dalla prima pulsazione conteggiata
unsigned long int tempo_trascorso_anemometro = 0; //conteggia il tempo trascorso dalla prima pulsazione
unsigned long int tempo_massimo_anemometro = 2000; //tempo (in millisecondi) dopo il quale calcolare la velocità e azzerare il numero di pulsazioni
//così non si conteggiano brevi folate di vento
unsigned long int inizio_elaborazione_anemometro;
float velocita_vento_max; //velocita vento massima misurata nelle 10 rilevazioni
float velocita_vento_min; //velocita vento minima misurata nelle 10 rilevazioni
//dati pluviometro
const float mmBasculata = 0.40; //millimetri per ogni basculata
const int pinPluviometro = 13;
int basculate = 0; //conteggio numero basculate
float mmPrecipitazioni = 0.0; //conteggio millimetri di pioggia
int stato_reed_pluviometro = 0;
int stato_reed_old_pluviometro = 0; //variabile per evitare doppie pulsazioni
//dichiarazione variabili ed array
int num_rilevazioni = 1;
float temperatura[10];
int umidita[10];
float pressione[10];
float luminosita[10];
float velocita_vento[10];
float temperatura_media;
float umidita_media;
float pressione_media;
float luminosita_media;
float velocita_vento_media;
float temperatura_tot;
float umidita_tot;
float pressione_tot;
float luminosita_tot;
float velocita_vento_tot;
float precipitazioni; //valore da trasmettere al database
void setup() {
delay(500);
//Serial.begin(9600);
//connessione Wifi
WiFi.begin(SSID, PASSWORD);
//impostazione avvio millis per lettura sensori
tempo_start_lettura_sensori = millis();
//inizializzazione I2C
Wire.begin();
//inizializzazione sensore BME280
sensore_temp_umid_press_BME280.begin(0x76);
//impostazione pin anemometro
pinMode(pinAnemometro, INPUT);
//impostazione pin pluviometro
pinMode(pinPluviometro, INPUT);
}
void loop() {
//reset di tempo_start_lettura_sensori in caso di overflow di millis che si azzera
if (millis()-tempo_start_lettura_sensori<0) {
tempo_start_lettura_sensori = millis();
}
//pluviometro
stato_reed_pluviometro = digitalRead(pinPluviometro); //legge il contatto reed
if (stato_reed_pluviometro != stato_reed_old_pluviometro){ //verifica se è cambiato lo stato
stato_reed_old_pluviometro = stato_reed_pluviometro; //se SI aggiorna lo stato
if (stato_reed_pluviometro == HIGH){ //controlla se lo stato è alto (passaggio magnete)
basculate++; //incrementa il numero di basculate
mmPrecipitazioni = mmPrecipitazioni + mmBasculata; //sommatoria millimetri di pioggia rilevati
}
}
//verifica se è trascorso l'intervallo per la lettura dei sensori
if ((millis()-tempo_start_lettura_sensori) > intervallo_lettura_sensori){
tempo_start_lettura_sensori = millis();
//anemometro
inizio_elaborazione_anemometro = millis(); //memorizza l'inizio dell'elaborazione (in caso di nessun impulso dopo tot tempo sospendiamo la rilevazione dell'anemometro)
while (tempo_trascorso_anemometro < tempo_massimo_anemometro) { //esegue fino a quando il tempo trascorso è minore al tempo massimo impostato
stato_reed_anemometro = digitalRead(pinAnemometro); //legge il contatto reed
if (stato_reed_anemometro != stato_reed_old_anemometro) { //verifica se è cambiato lo stato
stato_reed_old_anemometro = stato_reed_anemometro; //se SI aggiorna lo stato
if (stato_reed_anemometro == HIGH) { //controlla se lo stato è alto (passaggio magnete)
if (num_pulsazioni == 0) {tempo_start_anemometro = millis();} //se è il primo passaggio memorizza il tempo di partenza
num_pulsazioni = num_pulsazioni + 1; //aggiorna il contatore delle pulsazioni
tempo_trascorso_anemometro = (millis() - tempo_start_anemometro); //conteggia il tempo trascorso dallo start
}
}
delay(10);
if ((millis() - inizio_elaborazione_anemometro > 3000) || (inizio_elaborazione_anemometro > millis())) { //inizio_elaborazione_anemometro > millis() per effettuare un eventuale reset di millis (se millis torna a 0, quindi minore di inizio_elaborazione_anemometro)
tempo_trascorso_anemometro = tempo_massimo_anemometro;
}
}
float tempo_trascorso_anemometro_in_secondi = (tempo_trascorso_anemometro/1000.0); //converte in secondi
//velocita_vento[num_rilevazioni] = (3.6*num_pulsazioni*2*pigreco*raggio)/tempo_trascorso_anemometro_in_secondi; //velocità in km/h (formula iniziale non utilizzata)
//2 impulsi/sec -> velocità vento 5km/h quindi: 5km/h : 2 impulsi/sec = velcoità vento : (impulsi/secondo rilevati)
//coefficiente correzione attrito x2.5
velocita_vento[num_rilevazioni]=((num_pulsazioni/tempo_trascorso_anemometro_in_secondi) * 5 / 2) * 2.5;
num_pulsazioni = 0; //azzera il contatore delle pulsazioni per una nuova lettura
tempo_trascorso_anemometro = 0;
//sensore BME280
temperatura[num_rilevazioni]=sensore_temp_umid_press_BME280.readTemperature();
umidita[num_rilevazioni]=sensore_temp_umid_press_BME280.readHumidity();
pressione[num_rilevazioni]=sensore_temp_umid_press_BME280.readPressure();
//sensore fotoresistenza
luminosita[num_rilevazioni]=analogRead(pinFotoresistenza);
//operazioni da eseguire alla decima lettura eseguita
if (num_rilevazioni==10){
//azzeramento del contatore
num_rilevazioni=0;
//impostazione dei valori delle variabili prima del ciclo while
int i = 1;
temperatura_tot=0;
umidita_tot=0;
pressione_tot=0;
luminosita_tot=0;
velocita_vento_tot=0;
velocita_vento_max=0;
velocita_vento_min=1000;
precipitazioni=0; //valore da trasmettere al database
//scorre i dieci valori degli array
while (i<11) {
//calcolo del totale delle 10 rilevazioni per determinare la media
temperatura_tot=temperatura_tot+temperatura[i];
umidita_tot=umidita_tot+(float)umidita[i];
pressione_tot=pressione_tot+pressione[i];
luminosita_tot=luminosita_tot+luminosita[i];
velocita_vento_tot=velocita_vento_tot+velocita_vento[i];
//calcolo velocita_vento_max
if (velocita_vento[i]>=velocita_vento_max){
velocita_vento_max=velocita_vento[i];
}
//calcolo velocita_vento_min
if (velocita_vento[i]<=velocita_vento_min){
velocita_vento_min=velocita_vento[i];
}
i++;
}
//calcolo dei valori da trasmettere al database
temperatura_media=temperatura_tot / 10.00;
umidita_media=umidita_tot / 10.00;
pressione_media=pressione_tot / 10.00;
luminosita_media=luminosita_tot / 10.00;
velocita_vento_media=velocita_vento_tot / 10.00;
precipitazioni=mmPrecipitazioni;
//azzeramento valori pluviometro per prossime letture
basculate=0;
mmPrecipitazioni=0;
//trasmissione dati al server
if(WiFi.status()== WL_CONNECTED){
//verifica che il collegamento wifi sia attivo
String var="temp=" + String(temperatura_media) + "&umid=" + String(umidita_media) + "&pres=" + String(pressione_media) + "&lumi=" + String(luminosita_media) + "&velo=" + String(velocita_vento_media) + "&velo_max=" + String(velocita_vento_max) + "&velo_min=" + String(velocita_vento_min) + "&prec=" + String(precipitazioni);
String url = "GET /aggiungi.php?" + var + " HTTP/1.1";
//collegamento all'host
WiFiClientSecure client;
client.setInsecure(); //non si utilizzano certificati di sicurezza
if (client.connect(server, port)) {
//verifica che il collegamento col client sia andato a buon fine
client.println(url);
client.println("Host: www.xxx.it");
client.println("Access-Control-Allow-Origin: *");
client.println("Connection: close");
client.println();
delay(500); //delay fondamentale altrimenti a volte chiude la connessione prima che la pagina sia stata correttamente interrogata
client.stop();
}
}
}
num_rilevazioni=num_rilevazioni+1;
} //millis lettura sensori
} //loop
Oggi sono fuori tutto il giorno e quindi non riesco a provare il tuo sketch.
Se mi ricordo lo faccio domani.
Più che sulla bistrattata classe String, Io sposterei l'attenzione sul client wi-fi.
Mi sono già imbattuto in problemi simili in passato: in alcune condizioni il client secure crea un memory leak che rosicchia piano piano la quantità di memoria heap disponibile fino a quando questa non è più sufficiente per creare una nuova istanza del client.
Cosa importantissima: quale versione del core esp32 per Arduino stai usando?
se scrivi sulla posizione "[10]" vai a modificare un'area di memoria molto probabilmente utilizzata per altro, dal programma, e da qui mille possibili problemi.
Francamente, mi aspettavo un'eccezione immediata da parte dell'esp32 ed infatti lui non va a scrivere sulla posizione 10 perché azzera il contatore prima mi pare (sto guardando dal telefono)
Di sicuro però legge, andando quindi a sporcare in modo aleatorio la media delle letture.
Non è possibile prevedere cosa e quando si presentano i problemi, ma in genere i problemi che riscontri sono legati alla cattiva gestione della memoria.
float temperatura[10];
int umidita[10];
10 elementi da 4 byte seguiti da 10 elementi da 2 (*) byte allocati consecutivamente in ram. temperatura[10] legge/scrive 4 byte dall'array umidità.
(*) 4 byte su architettura 32-bit (ESP-32)
PS: gli array e puntaori sono le prime cose che si dovrebbero studiare tanto bene da entrare nel nostro dna, ma non è cosa fattibile e l'errore capita anche al programmatore esperto che però sa riconoscere l'anomalia e cerca nel codice errori con gli indici.
Ciao.
Ed il fatto che quando alimento l'esp32 non parte il codice e devo sempre premere reset dipende sempre dal codice?
Ho provato anche a collegare un condensatore di 10uF tra il pin EN E GND come letto in alcuni topico ma non funziona.