SafeString: conversione da numero a SafeString

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?

Grazie mille

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 :wink:

Guglielmo

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 :wink:

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 ... :roll_eyes:

Hai provato a guardare anche tra gli esempi della libreria?
Con la classe String che "operatori" useresti? La stessa cosa con la SafeString ...

Guglielmo

Ho risolto utilizzando questa modalità:

stringainiziale = "testo iniziale";   //stringainiziale è un oggetto SafeString
int numero += 3;
stringainiziale += numero;

Riscontro però, superati circa i 200 caratteri (sto componendo un url), il seguente problema:

Guru Meditation Error: Core  1 panic'ed (InstrFetchProhibited). Exception was unhandled.

Core  1 register dump:
PC      : 0xc000b83f  PS      : 0x00060b30  A0      : 0x800d9a05  A1      : 0x3ffb2180  
A2      : 0x3ffc3b1c  A3      : 0x3ffc35ec  A4      : 0x0000009d  A5      : 0x00000000  
A6      : 0x00000012  A7      : 0xff000000  A8      : 0x80177ce6  A9      : 0x3ffb2160  
A10     : 0x3ffc35ec  A11     : 0x3ffc3b1c  A12     : 0x00000000  A13     : 0x00000012  
A14     : 0x000000af  A15     : 0x00000000  SAR     : 0x00000015  EXCCAUSE: 0x00000014  
EXCVADDR: 0xc000b83c  LBEG    : 0x4008a1c9  LEND    : 0x4008a1d9  LCOUNT  : 0xfffffffd  

Backtrace: 0x4000b83c:0x3ffb2180 0x400d9a02:0x3ffb21a0 0x400d2df1:0x3ffb21c0 0x400dd87c:0x3ffb2270 0x4008ec4a:0x3ffb2290

ELF file SHA256: fa537c9bf87a3fab

Rebooting...

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?

Serial.println("temperatura=" + String(temperatura_media));

Grazie mille

... come hai dimensionato, in fase di creazione, la SafeString 'stringainiziale'?

createSafeString(stringainiziale, ???);

Guglielmo

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...

Avendo un url di circa 220 caratteri, ho impostato:

createSafeString(stringainiziale, 250);

C'è un limite massimo?

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.

Sono pronto a scommettere che non dipende da quello.

Prova a mettere lo sketch completo su vuoi.

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

Grazie mille

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?

float temperatura[10];
int umidita[10]; 

10 elementi indicizzati da 0÷10 - 1. Indice massimo valido 9.

1 Like

Io lo dico sempre che accanirsi sulla classe String distoglie l'attenzione da errori ben più gravi :roll_eyes:

Grazie per la segnalazione, ma indicare [10] al posto di [9] che problemi può generare?

un array si dichiara quanto "lungo" è...poi i suoi "posti" iniziano dallo "0"...come detto da Maurotec...se dichiari un array come:

int mioArray[10];

vuol dire che devi contare così:

mioArray[0];
mioArray[1];
mioArray[2];
mioArray[3];
mioArray[4];
mioArray[5];
mioArray[6];
mioArray[7];
mioArray[8];
mioArray[9];

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.

Provvedo sicuramente a correggere grazie mille.

Nel mio caso che scrivo dalla posizione 1 alla 10 e semplicemente non scrivo nella posizione 0, può comunque creare 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.