Bonjour,
La réception de SMS pour permettre de commander principalement des relais pour éclairage, chauffage, simulation de présence... peut-être utile.
Evidemment, il y a déjà des topics à ce sujet mais j'ai eu quelques des difficultés à les mettre en place pour diverses raisons.
Voici une solution de récupération du contenu d'un SMS, c'est un exemple parmi d'autres...
Le matériel :
- Module Iduino Uno
- GPRS Shield SIM900 (geeetech)
Ma seule librairie SoftwareSerial.h est inévitable.
Il n'y a pas de contrôle de dépassement de mémoire, mes messages doivent donc faire moins de 30 octets, suffisant pour un protocole simple.
SoftwareSerial Sim900(7,8);
// variables
char bufRecSim900[512]; // buffer de réception
int cptRecSim900; // compteur
char bufIndexSMS[10]; // pour memorisation index du message
int cptIndex;
char bufIndex[10]; // pour l'index en chaine de caracteres brut
char *ptrIndex; // pointeur tempraire pour traitement de l'index
char cmdSim900[30]; // pour les commandes à destination du Sim900
int litSMS=0; // drapeau pour signaler que la prochaine ligne est le contenu du SMS
bool recommence=true; // pour la boucle de lecture des données venant du SIM
char c; // pour traiter un caractère
Initialisation du Sim900 (et de la liaison série avec le PC pour vérification)
void setup()
{
Sim900.begin(19200); // the GPRS baud rate
Serial.begin(19200); // le PC pour verification
delay(500);
}
Dans la boucle, deux parties :
void loop()
{
// lecture des données qui arrivent du Sim900
// traitement des données
}
Première partie, lecture des données :
on attend la réception d'un caractère NL ou CR qui signale qu'une ligne a été reçue (=> cptRecSim900 = 64), on peut la traiter.
if (Sim900.available()) {
while(Sim900.available()) {
// utilisation de peek pour rechercher le caractère NL et CR
c = Sim900.peek();
switch(c) {
case '\x0a' :
case '\x0d' :
Sim900.read();
if (cptRecSim900 > 0) {
bufRecSim900[cptRecSim900++] = '\x0a';
bufRecSim900[cptRecSim900++] = '\0';
cptRecSim900 = 64;
}
break;
default :
bufRecSim900[cptRecSim900++] = Sim900.read();
break;
}
if(cptRecSim900 == 64) break;
}
}
Dans la seconde partie qui s'exécute si cptRecSim900 = 64, on y trouve 3 parties :
- Attente du code "+CMTI:" qui signale qu'un message est arrivé
=> récupération de l'index
=> envoie de la commande pour lire le message "AT+CMGR=\r"
// On attend un +CMTI:
if (strstr(bufRecSim900, "+CMTI:")) {
// Un nouveau message est arrivé, il faut récupérer l'index du message
// Le format est "+CMTI: "SM",<index>"
ptrIndex = strchr(bufRecSim900, ',');
// L'index se trouve juste après le caractère ',' donc du pointeur ptr + 1
ptrIndex++;
sprintf(bufIndex, "%s", ptrIndex);
cptIndex = 0;
// il faut enlever les caracteres parasites comme \x0a
while(1) {
if ( (bufIndex[cptIndex] < '\x30') || (bufIndex[cptIndex] > '\x39') ) {
bufIndex[cptIndex] = '\0';
// on sort du while
break;
}
cptIndex++;
}
sprintf(cmdSim900, "AT+CMGR=%s\r", bufIndex);
Sim900.write(cmdSim900);
}
- Attente du code "+CMGR" qui indique que la ligne suivante est le message ==> litSMS = 1
// on peut comparer le début de ligne
if (strstr(bufRecSim900, "+CMGR:")) {
litSMS = 1;
}
- Si litSMS, alors lecture du message et donc traitement...
if (litSMS) {
// c'est ici que l'on passe au traitement du contenu du SMS
// dans mon cas, je l'affiche...
Serial.print(bufRecSim900);
// on repasse le drapeau à 0 pour l'attente d'un nouveau SMS
litSMS = 0;
}
Attention, il faut tester le drapeau litSMS en premier ! et de repasser le cptRecSim900 à 0...
#include <SoftwareSerial.h>
SoftwareSerial Sim900(7,8);
// variables
char bufRecSim900[512]; // buffer de réception
int cptRecSim900; // compteur
char bufIndexSMS[10]; // pour memorisation index du message
int cptIndex;
char bufIndex[10]; // pour l'index en chaine de caracteres brut
char *ptrIndex; // pointeur tempraire pour traitement de l'index
char cmdSim900[30]; // pour les commandes à destination du Sim900
int litSMS=0; // drapeau pour signaler que la prochaine ligne est le contenu du SMS
bool recommence=true; // pour la boucle de lecture des données venant du SIM
char c; // pour traiter un caractère
void setup()
{
Sim900.begin(19200); // the GPRS baud rate
Serial.begin(19200); // le PC pour verification
delay(500);
}
void loop() {
if (Sim900.available()) {
while(Sim900.available()) {
// utilisation de peek pour rechercher le caractère NL et CR
c = Sim900.peek();
switch(c) {
case '\x0a' :
case '\x0d' :
Sim900.read();
if (cptRecSim900 > 0) {
bufRecSim900[cptRecSim900++] = '\x0a';
bufRecSim900[cptRecSim900++] = '\0';
cptRecSim900 = 64;
}
break;
default :
bufRecSim900[cptRecSim900++] = Sim900.read();
break;
}
if(cptRecSim900 == 64) break;
}
}
// si cptReception = 64, la ligne est entière
if (cptRecSim900 ==64) {
if (litSMS) {
// c'est ici que l'on passe au traitement du contenu du SMS
// dans mon cas, je l'affiche...
Serial.print(bufRecSim900);
// on repasse le drapeau à 0 pour l'attente d'un nouveau SMS
litSMS = 0;
}
// on peut comparer le début de ligne
if (strstr(bufRecSim900, "+CMGR:")) {
litSMS = 1;
}
// On attend un +CMTI:
if (strstr(bufRecSim900, "+CMTI:")) {
// Un nouveau message est arrivé, il faut récupérer l'index du message
// Le formt est "+CMTI: "SM",<index>"
ptrIndex = strchr(bufRecSim900, ',');
// L'index se trouve juste après le caractère ',' donc du pointeur ptr + 1
ptrIndex++;
sprintf(bufIndex, "%s", ptrIndex);
cptIndex = 0;
// il faut enlever les caracteres parasites comme \x0a
while(1) {
if ( (bufIndex[cptIndex] < '\x30') || (bufIndex[cptIndex] > '\x39') ) {
bufIndex[cptIndex] = '\0';
// on sort du while
break;
}
cptIndex++;
}
sprintf(cmdSim900, "AT+CMGR=%s\r", bufIndex);
Sim900.write(cmdSim900);
}
// la ligne a ete traite, cptRecSim900 repasse à 0
cptRecSim900 = 0;
}
}
Voilà !