Sim800l - lettura e scrittura valori da e per sms

Chiedo anticipatamente scusa perché, anche se con tutta probabilità ci saranno, non sono riuscito a trovare sul web e sul forum le informazioni che mi servivano. (avrò sbagliato le parole chiavi per la ricerca).

Comunque, senza perdermi troppo in chiacchiere
ho il seguente programma:
-Riceve un sms con su scritto "Verifica" da un numero telefonico prestabilito e retituisce le letture di 6 sensori di temperatura;
-invia un sms di errore se una specifica sonda di temperatura supera una certa soglia

il problema invece è il seguente
-no matching function for call to 'Sim800l::sendSms(String&, String&)'

la mia domanda è
-Se la funzione vuole due stringhe, ed io gli ho dato due stringhe, perché mi da errore? cosa sto sbagliando (a prescindere dal resto del codice che potrebbe essere sbagliato)
-Devo convertire in qualche modo le stringhe?

Questo è il link per la libreria del modulo SIM800l ed a seguire lascio il codice

//Inserimento librerie
#include <Sim800l.h> //Libreria del combinatore SIM800l
#include <SoftwareSerial.h> //Parametro necessario per la libreia del combinatore
Sim800l Sim800l; //dichiarazione della libreria
#include <stdio.h> //Per le conversioni da float a stringa
#include <string.h> //Per lavorare con le strighe 

//Inserimento parametri
float sogliaTemp = 60.00; //in gradi centigradi, è la soglia sotto la quale l'accumulo del boiler non può scendere
char numAzienda[14]="+39"; //Stringa contenente il numero dell'AZIENDA
char numTecnico[14]="+39"; //Stringa contenente il numero del TECNICO
char numCliente[14]="+39"; //Stringa contenente il numero del CLIENTE
char nomeCliente[]="Hotel X"; //Stringa contenente il NOME del CLIENTE
bool inviato; //Variabile per conferma invio SMS

//definizione parametri provenienti da modulo gsm
String smsRicevuto; //Stringa che conterrà il testo del messaggio ricevuto
String numSmsRicevuto; //Stringa che conterrà il numero di telefono del messaggio ricevuto

//Variabili che immagazzineranno tutte le temperature (in gradi centigradi) dai sensori
float bMax, bMin, bOut, cIn, cOut, sIn, sOut, tA;

//Modelli di testo per SMS
char erroreComando[]="Comando non valido, riprovare"; //Stringa contenente il testo di errore dei comandi ricevuti per sms
char allertaAzienda[]="Attenzione: rilevato abbassamento della temperatura ACS dell'impianto"; //Stringa contenente il testo allerta per l'azienda e il tecnico
char allertaCliente[]="Guasto impianto ACS: Il tecnico verrà a verificare l'impianto nel più breve tempo possibile"; //Stringa contenente il testo allerta per il cliente
char smsTemperature[]="Temperature impianto";//Stringa contenente il messaggio con tutte le temperature dell'impianto

//definizione dei nomi degli input analogici (sonde temperatura)
#define boilerMax A0 //Sonda boiler superiore
#define boilerMin A1 //Sonda boiler inferiore
#define boilerOut A2 //Sonda uscita ACS boiler
#define caldaiaIn A3 //Sonda ingresso acqua caldaia
#define caldaiaOut A4 //Sonda uscita acqua caldaia
#define solareIn A5 //Sonda ingresso acqua pannello solare
#define solareOut A6 //Sonda uscita acqua pannello solare
#define tempAmbiente A7 //Sonda temperatura ambiente



void setup(){
	Sim800l.begin(); //Inizializza la libreria del modulo gsm 
  Sim800l.reset(); //Resetta il modulo gsm
  Sim800l.delAllSms(); //All'avvio, il programma cancella tutti i messaggi in memoria
  delay(5000); //Attendi 5 secondi
}//void setup



void loop(){
//LETTURA ED IMMAGAZZINAMENTO TEMPERATURE DAI SENSORI con conversione in gradi centigradi
  bMax=(float)analogRead(boilerMax)*0.2882d;  delay(100);
  bMin=(float)analogRead(boilerMin)*0.2882d;  delay(100);
  bOut=(float)analogRead(boilerOut)*0.2882d;  delay(100);
  cIn=(float)analogRead(caldaiaIn)*0.2882d;   delay(100);
  cOut=(float)analogRead(caldaiaOut)*0.2882d; delay(100);
  sIn=(float)analogRead(solareIn)*0.2882d;    delay(100);
  sOut=(float)analogRead(solareOut)*0.2882d;  delay(100);
  tA=(float)analogRead(tempAmbiente)*0.2882d; delay(100);


//LOOP RICEZIONE, SALVATAGGIO E MODIFICA SMS (con testo tutto grande)
  smsRicevuto=Sim800l.readSms(1); //Legge il primo SMS (ovvero nella posizione 1) in memoria e lo inserisce nella stringa "messaggioRicevuto"
  smsRicevuto.toUpperCase(); //imposta tutti i caratteri dell'SMS in maiuscolo
  numSmsRicevuto=Sim800l.getNumberSms(1); //legge e memorizza il numero telefonico del primo sms in memoria (ovvero il numero di telefono da cui ha ricevuto l'SMS)

 
//LETTURA CONTENUTO SMS (AZIENDA)
  if(numSmsRicevuto.indexOf(numAzienda)!= -1){ //Se l'SMS è stato ricevuto dall'azienda
     if(smsRicevuto.indexOf("VERIFICA")!= -1){ //e contiene il comando (ovvero la parola) "verifica"
        Sim800l.sendSms(numAzienda,smsTemperature); //invia un sms con tutte le temperature all'azienda
        delay(3000); //attendi 3 secondi dopo l'invio dell'SMS
      }else{Sim800l.sendSms(numAzienda,erroreComando);} //uscita If controllo grandezza testo SMS
   }//uscita If controllo numeri di telefono (e uscita IF generale)


//LETTURA CONTENUTO SMS (TECNICO)
  if(numSmsRicevuto.indexOf(numTecnico)!= -1){ //Se l'SMS è stato ricevuto dal tecnico
     if(smsRicevuto.indexOf("VERIFICA")!= -1){ //e contiene il comando (ovvero la parola) "verifica"
        Sim800l.sendSms(numTecnico,smsTemperature); //invia un sms con tutte le temperature al tecnico
        delay(3000); //attendi 3 secondi dopo l'invio dell'SMS
      }else{Sim800l.sendSms(numTecnico,erroreComando);} //uscita If controllo grandezza testo SMS
    }//uscita If controllo numeri di telefono (e uscita IF generale)
    

//CANCELLAZIONE DELLA MEMORIA DEGLI SMS (se riceviamo sms da sconosciuti o per pulire la memoria dopo aver ricevuto/inviato sms di cui sopra)  
    Sim800l.delAllSms(); //Cancella tutti gli SMS in memoria
    smsRicevuto=""; //Svuota la memoria della stringa riservata all'SMS (pronta per immagazzinarne uno nuovo)
    numSmsRicevuto=""; //Svuota la memoria della stringa riservata al numero (pronta per immagazzinarne uno nuovo)
    delay(1000); //per non far andare troppo veloce il codice dopo i comandi di cancellazione


//CONTROLLO DELLE TEMPERATURE CON ANNESSA SEGNALAZIONE TRAMITE SMS
  if(bMax <= sogliaTemp){ //Se la temperatura rilevata dalla sonda superiore del boiler è scesa sotto la soglia minima impostata
    inviato=Sim800l.sendSms(numAzienda,allertaAzienda); //Invia SMS di allerta all'azienda
    delay(1500);
    if(inviato){ //Se il primo SMS è stato inviato
      inviato=Sim800l.sendSms(numAzienda,smsTemperature); //Invia un secondo SMS con le temperature dell'impianto all'azienda
      delay(1500);
      if(inviato){ //Se il secondo SMS è stato inviato
        inviato=Sim800l.sendSms(numTecnico,allertaAzienda); //Invia SMS di allerta al tecnico
        delay(1500);
        if(inviato){ //Se il terzo SMS è stato inviato
          inviato=Sim800l.sendSms(numTecnico,smsTemperature); //Invia un secondo SMS con le temperature dell'impianto al tecnico
          delay(1500);
          if(inviato){ //Se il quarto SMS è stato inviato
            inviato=Sim800l.sendSms(numCliente,allertaCliente); //Invia SMS di allerta al cliente
            delay(1500);
            }}}}}
    

}//void loop

Chiedo di nuovo scusa se ho sbagliato sezione e/o se non sono riuscito a trovare la risposta sul forum/web.

Grazie mille anticipatamente per l'aiuto.

... probabilmente perché tu stai usando la classe String, mentre quella libreria è fatta, correttamente, usando le stringhe classiche del 'C' ... due cose ben diverse !

Se avessi studiato gli esempi avresti difatti visto che NON usano la classe String, ma dei "char array", ovvero, come detto le stringhe classiche del 'C'.

Guglielmo

Ah, aggiungo una nota che metto sempre (la troveria in decine di miei post) per chi usa la classe String su Arduino ...

... NON sei su un PC dove c'è un sistema operativo ed un "garbage collector", sei su una piccola MCU con solo 2KBytes di SRAM, dove devi fare tutto tu e dove usare la classe "String", a causa dell'allocazione e riallocazione dinamica della memoria, porta quasi sempre ... a grossi problemi e sicuri mal di testa !!! :smiling_imp:

Impara ad usare le stringhe classiche del C ... ovvero semplici array di char terminati dal carattere null (0x00) e le funzioni che trovi nella libreria standard (... che, oltretutto, è automaticamente inclusa dal IDE) AVR libc ed, in particolare, quanto è in <string.h> :slight_smile:

Guglielmo

gpb01:
... probabilmente perché tu stai usando la classe String, mentre quella libreria è fatta, correttamente, usando le stringhe classiche del 'C' ... due cose ben diverse !

Se avessi studiato gli esempi avresti difatti visto che NON usano la classe String, ma dei "char array", ovvero, come detto le stringhe classiche del 'C'.

Guglielmo

Ciao Guglielmo, grazie per la delucidazione.

Ho visto più volte gli esempi ma essendo che sono alle prime armi, ancora a molte cose non ci arrivo. Sopratutto con le stringhe sto facendo un po di difficoltà a capirle.
è ovvio che devo studiare in maniera molto più approfondita la cosa.

Quindi basta semplicemente mettere char nomeStringa[]="testo"; laddove ho messo la parola "String" (opportunamente adattato) per risolvere il problema? in questo modo, nella parte dove compongo l'sms non perdo la concatenazione dei testi?

grazie

gekolas:
... in questo modo, nella parte dove compongo l'sms non perdo la concatenazione dei testi?

Certo che la perdi, con le VERE stringhe del 'C' quelle "porcherie" non si fanno :smiley: :smiley: :smiley:

Non per nulla ti ho linkato quello che devi studiare, ci sono apposite funzioni 'C' per concatenare le stringhe ... ad esempio guarda la strlcat() ... :wink:

Guglielmo

gpb01:
Certo che la perdi, con le VERE stringhe del 'C' quelle "porcherie" non si fanno :smiley: :smiley: :smiley:

Non per nulla ti ho linkato quello che devi studiare, ci sono apposite funzioni 'C' per concatenare le stringhe ... ad esempio guarda la strlcat() ... :wink:

Guglielmo

Perfetto Guglielmo, grazie mille.
dopo le modifiche grazie a tuoi consigli, l'IDE riesce a verificare il codice (un piccolo passo in avanti)

Ora quindi non mi resta che:

  • trasformare i valori float che leggo dai sensori di temperatura in stringhe e...
  • concatenare tutte le stringhe per l'invio dell'sms.

Avresti altri buoni consigli da dispensare a riguardo?

poi ho notato che la Sim800l vuole in pasto array di caratteri ma restituisce Stringhe quando legge il numero telefonico e/o l'SMS ricevuto...
a questo punto mi sorge una domanda: quando faccio il controllo del numero o del testo dell'sms, il programma gira lo stesso o, anche se la compilazione va a buon fine, si impallerà una volta in funzione?

...una bella gatta da pelare insomma; ma ci sto prendendo gusto. :slight_smile:
(ps. aggiorno il primo post sostituendo il codice con quello attuale)

... effettivamente li l'autore della libreria ha perso un'occasione per fare un bel lavoro ed ha usato, non si capisce perché, la classe String.

Comunque, tu ricorda che data una String la trasformi facilmente in un char array. Ti faccio un esempio ...

String pippo;
char   mioArray[20];
....
strncpy(mioArray, pippo.c_str(), sizeof(mioArray));

... ovvero, se vuoi una stringa classica del 'C' a partire da una String basta che a tale String aggiungi ".c_str()" e quello che hai è un "char array" con cui lavorare come ti ho indicato.

Il grande vantaggio dei "char array" è che sono preallocati, quindi, basta che li dimensioni bene all'inizio (ricorda sempre un carattere in più per il terminatore 0x00 che indica la fine della stringa di caratteri) e non hai problemi.

Guglielmo

P.S.: strncpy() si trova sempre in <string.h> in AVR libc

Grande vantaggio non direi in quanto potrebbero creare problemi. La classe Stringa ha il controllo su tutto quello che succede ed è più sicura soprattutto per chi non conosce bene i problemi della programamzione in C.

Quella funzione "non" è dichiarata correttamente perchè permette il passaggio di un puntatore non costante, e in quel caso è sbagliato, visto che non dovrebbe modificare nulla.

Usare la String è giusto perchè lo ha protetto e gli ha fatto capire (doveva capirlo) che quella funzione prende un parametro non costante. Poi non dovrebbe succedere nulla, però è un errore.

L'errore è di chi ha creato quella libreria e non di chi ha usato String per chiamare la funzione, anche se poi si capisce che i parametri sono diversi.

tonioB:
Grande vantaggio non direi in quanto potrebbero creare problemi. La classe Stringa ha il controllo su tutto quello che succede ed è più sicura soprattutto per chi non conosce bene i problemi della programamzione in C.

Ma quali problemi? :o :o :o ... giusto se sbagli a dimensionare o scrivi oltre la fine dell'array ...

La classe String, su una MCU come quella di Arduino ... è una bojata pazzesca ed è completamente da evitare, altro che il controllo su tutto ... il controllo su nulla (Vd. mio post #2 sopra).

Guglielmo

Dici nulla ?
l'errore nel dimensionamento e scrivere oltre l'array sono "gravi" e spesso neppure te ne accorgi dell'errore.
Questi errori possono succedere ancora di più se lo usi con librerie diverse e gestioni diverse di utenti magari incapaci.

La String può essere anche "preallocata" senza i problemi che citi.

Se vuoi la gestione sicura non devi usare gli array per le stringhe appunto perchè non esiste un GB che lo faccia al posto tuo.

Poi ovvio che usare la classe String richieda un "minimo" di spazio in più in memoria, ma non sono dovuti alla riallocazione, anche perchè esiste di default un minimo già preallocato senza usare altre funzioni.

NON sono affatto d'accordo e ... il 80% del mondo MCU (lascia stare la programmazione su PC che è tutt'altro mondo) per "applicazioni reali" (... automotive, medicale, spaziale, ecc) è 'C' puro, senza "classi" o altro ...
... fatti qualche domanda ... ::slight_smile:

Guglielmo

Non mi devo fare nessuna domanda, ti ho dato delle spiegazioni. Programmo da 30 anni e un "minimo" di esperienza l'ho accumulata.

Dai Guglielmo poi non è così importante, giustamente hai la tua opinione ed io la mia, l'importante far conoscere i problemi :slight_smile:

tonioB:
Non mi devo fare nessuna domanda, ti ho dato delle spiegazioni. Programmo da 30 anni e un "minimo" di esperienza l'ho accumulata.

... lo faccio da almeno 12 anni prima di te :grin:

Il problema è che tu probabilmete programmi su "sistemi" io essenzialmente su "microcontrollori" e le cose sono ben diverse ...

tonioB:
Dai Guglielmo poi non è così importante, giustamente hai la tua opinione ed io la mia, l'importante far conoscere i problemi :slight_smile:

... concordo, oltretutto siamo parecchio OT :smiley: :smiley: :smiley:

Guglielmo

Tornando IT, il programma non ha particolari esigenze e programmarlo in modo sicuro dovrebbe essere la regola di partenza.

Purtroppo quella libreria non è stata scritta benissimo (però sinceramente ho dato un'occhiata veloce) e richiede un certo tipo di parametri per le funzioni.

Guglielmo, parlare di sicurezza è un conto e spazio in memoria un altro. Poi le schifezze si fanno su tutti i sistemi quando hai "esigenze particolari".

Rieccomi, intanto volevo ringraziarvi entrambi per la pazienza e l'interesse dimostrato.

Tornando alla programmazione, anche se sono sicuro di essere molto vicino al completamento della scrittura, sto incontrando non poche difficoltà:

-mi resta da convertire dei valori float (temperatura da sensori tmp36) in char array e
-concatenare tutti i char array per formare l'sms da inviare al numero che ne ha fatto richiesta.

ho provato studiare un pò i link e i pezzi di codice che mi ha mandato Gugliemo ma la compilazione mi restituisce diversi errori.

sto avendo poco tempo da dedicare al progetto e mi sento sempre più frustrato quando provo a sistemare il codice senza risultati.

Grazie

Per la concatenazione delle stringhe hai la strlcat() che sta in <string.h>.

Naturalmente, quando concateni la stringa A alla stringa B, la stringa B deve già essere stata dimensionata per contenere la somma delle due stringhe ... ovvero, la stringa di destinazione finale deve essere già stata dimensionata per il massimo che deve contenere (... più un carattere per lo 0x00 finale)

Guglielmo

La conversione invece di un float in una stringa classica è un piccolo problema dato che, per ragioni di occupazione di memoria (i float e le operazioni su di essi sono molto pesanti), è stata eliminata dalla AVR libc.

In allegato ti passo una piccola funzione che ti permette di fare detta conversione con la precisione che vuoi tu ...

Metti il file nella stessa cartella dove si trova il .ino ed includilo in testa la tuo programma con la:

#include "floatToString.h"

... guarda i commenti interni per i parametri da passargli e per un semplice esempio (... essenzialmente vuole 4 parametri: 1.la stringa dove vuoi mettere il risultato della conversione, 2.il numero float, 3.quanti decimali vuoi, 4.se vuoi l'allineamento a destra, la lunghezza fissa che vuoi, altrimenti il valore 0).

Guglielmo

floatToString.h (1.71 KB)

gpb01:
Per la concatenazione delle stringhe hai la strlcat() che sta in <string.h>.
...

Mi sembra però di aver capito che posso concatenare solo due stringhe...
se voglio concatenarne di più, devo concatenare l'output data dall'unione di due stringhe con una terza stringa? (o con una stringa nata dall'unione di altre due?) è corretto?

è vero che mi hai già spiegato che conviene lavorare con le stringhe 'c', ed è quello che farò, ma se lavorassi tutti i dati con "String" (acquisizione dati, conversione e concatenazione) e poi facessi la conversione di questa lunga String in char array? potrebbe essere una soluzione alternativa?
Faccio la domanda giusto per capire.

Grazie comunque per le risposte.

E' molto semplice, tu crei una stringa vuota della lunghezza massima che ti serve (... esempio, faccaimo 80 caratteri):

char miaStringa[80] = {0x00};  // metti 0x00 nel primo carattere ad indicare che è vuota

... dopo di che attacchi una dopo l'altra le varie stringhe concatenandole a questa vuota. Esempio, attacchiamo "Pippo, " poi "Pluto, " e poi "Paperino."

strlcat(miaStringa, "Pippo, ", 80);
strlcat(miaStringa, "Pluto, ", 80);
strlcat(miaStringa, "Paperino.", 80);

... a questo punto la tua stringa miaStringa conterrà "Pippo, Pluto, Paperino." ovvero 23 caratteri più, come sempre, lo 0x00 finale (quindi 24 caratteri), numero di caratteri che stanno tranquillamente in miaStringa che avevamo fissato con lunghezza di 80 caratteri. :slight_smile:

Ovviamente, oltre a delle stringhe fisse, come ho scritto nell'esempio qui sopra, puoi concatenare anche altre varibili stringa ... l'importante è aver ben dimensionato la prima in modo che la strlcat() non sia costretta a troncare il concatenamento perché non c'è spazio.

E NO, la tua soluzione NON va bene perché ricadiamo nel problema della classe String. :wink:

Guglielmo

Di nuovo grazie Guglielmo per le dritte.
finalmente, ho avuto un po di tempo per assemblare il circuito e caricare il programma sul mio nano (Old Bootloader).

Una volta caricato il programma però, ho notato che il led TX sul mio nano resta acceso.
leggendo un po qua e la mi è sembrato di capire che non è una cosa normale. :o
Nella ricerca del problema mi sono imbattuto in diversi post di persone che, usando il modulo Sim800l, hanno avuto problemi di comunicazione ed hanno dovuto modificare i pin nel file sim800l.h

Ora, leggendo quel file (LINK), noto che i pin sono settati così come li ho collegati io (vedi immagine allegata).

A questo punto mi chiedo: perchè il led TX sul nano resta sempre acceso? potrebbe essere qualche riga di codice scritta male?

premetto che ancora non ho montato la sim per fare le relative prove; mi chiedevo inoltre se c'è un modo per verificare che il modulo comunichi con arduino senza problemi.
Grazie