Blog

Envoi de sms depuis un module de developpement A9G pudding

Et oui! encore un article sur l’envoi de SMS! Cette fois nous allons le faire depuis un module A9G pudding. J’espère que ce sera le deuxième dans une série sur ce module. Mon projet est de faire un système de suivi GPS avec enregistrement du tracé sur une carte SD et envoi à la demande de la position par sms.

Je reprend là où j’ai laissé l’article précédent (
https://www.twiggotronix.com/fr/a9g-pudding-module-de-developpement/ ) qui explique comment mettre en place le sdk et uploader notre premier programme.

J’ai créé un repo sur github où vous pourrez trouver le code relatif à cet article :
https://github.com/twiggotronix/a9g-pudding-sms

J’avoue que je me suis grandement inspiré des exemples de démo qui sont plutôt bien faits. Ce code va envoyer un sms au démarrage du module pour signaler qu’il est en route et puis renvoyer le contenu des messages qu’il reçoit.

Configuration

La seule configuration est celle du numéro de téléphone qui va recevoir les messages. Il suffit de dupliquer le fichier include/app_main_example.h, le renommer en include/app_main.h et renseigner le numéro de téléphone (j’ai pas essayé d’autres formats mais ça marche bien avec le format “+336XXXXXXXX”). Cette manipulation permet d’ignorer le fichier dans git.

vous pouvez compiler et uploader le code comme ça et vous devriez recevoir un message contenant ” Ready and able! “.

Evénements

Nous pouvons savoir quand le module est enregistré sur le réseau et pret à communiquer (ou non en cas d’erreur) grâce aux événements. A chaque événement, la fonction EventDispatch est appelé avec un objet contenant des informations décrivant ce qu’il c’est passé (dans la boucle while de la tâche principale ). Par exemple, lorsque l’id de l’événement correspond à la constante API_EVENT_ID_NETWORK_REGISTER_SEARCHING , cela signifie que le module est en train de chercher le réseau. Vous pouvz trouver la liste des événements possibles dans /include/api_inc/api_event.h. l’événement

void EventDispatch(API_Event_t* pEvent)
{
    
    switch(pEvent->id)
    {
        case API_EVENT_ID_NO_SIMCARD:
            Trace(10,"!!NO SIM CARD%d!!!!",pEvent->param1);
            break;
       ....
    }
}

Note: Au moment où je pensais avoir quelque chose de stable, le module a arrêté de communiquer correctement… En ajoutant un cas dans le switch, j’ai pu voir que j’avais une erreur d’enregistrement sur le réseau ( API_EVENT_ID_NETWORK_REGISTER_DENIED ). Je ne suis pas sûr mais j’ai l’impression que cette erreur est venue du fait que mon antenne c’est détachée du module qui s’est mis à remarcher depuis…

Envoi de messages

Pour envoyer un message j’ai créé la fonction SendSMS (j’ai juste extrait la partie du code qui gère l’envoi dans la demo sms) qui prend en paramètre uint8_t message[] et l’envoi au numéro paramétré.

void SendSMS(uint8_t message[])
{
    uint8_t* unicode = NULL;
    uint32_t unicodeLen;
 
    Trace(1,"sms start send UTF-8 message");
 
    if(!SMS_LocalLanguage2Unicode(message,strlen(message),CHARSET_UTF_8,&unicode,&unicodeLen))
    {
        Trace(1,"local to unicode fail!");
        return;
    }
    if(!SMS_SendMessage(PHONE_NUMBER,unicode,unicodeLen,SIM0))
    {
        Trace(1,"sms send message fail");
    }
    OS_Free(unicode);
}
 
SendSMS("Ready and able!");

Réception des messages

Lors de la réception de l’événement API_EVENT_ID_SMS_RECEIVED on peut récupérer le contenu du message dans l’attribut pParam2 (pEvent->pParam2). Dans mon code, la fonction messageRecieved récupère le contenu et le renvoi par sms. Vous pouvez aussi récupéré le numéro qui a envoyé le sms reçu dans l’attribut pParam1 (qui contient les entêtes du message) mais ça demande un peu plus de travail pour l’extraire de la chaîne de caractères. N’hesitez pas à nous dire comment vous vous y prendrez!

void messageRecieved(uint8_t* content)
{
    char buffer[200];
    snprintf(buffer, sizeof(buffer), "Message received : %s", content);
    Trace(1, buffer);
    SendSMS(buffer);
}

void EventDispatch(API_Event_t* pEvent)
{
    switch(pEvent->id)
    {
        case API_EVENT_ID_SMS_RECEIVED:
            Trace(2,"received message");
            uint8_t* content = pEvent->pParam2;

            Trace(2,"message header:%s",header);
            Trace(2,"message content length:%d",contentLength);
            messageRecieved(content);            
            break;
    }
}

A9G pudding – GRPS, GPS et microcontrôleur tout en un

Ce petit module à tout faire est doté, en plus d’un nom qui donne faim, de fonctionnalités incroyables :

GPS, SMS, Appels, Internet, Emplacement carte flash, Entrées/Sorties à foison, et plein d’autres encore …

Ce module répond aux commandes AT comme pour les modules A6 et A7, mais je ne me suis pas trop intéressé à cet aspect car il est aussi programmable directement en C++!!! Du coup, pas besoin d’un autre microcontrôleur à côté!! On réduit donc les coûts, l’encombrement et la puissance nécessaire.

L’installation des dépendances sous Windows est un peu laborieux et n’est pas hyper intuitif, mais une fois que tout est en place c’est assez simple!

Branchement :

Branchez votre module de programmation FTDI au module comme ceci :

Programmateur FTDIModule A9G
RXHST_TX
TXHST_RX
GNDGND
VCCNE PAS BRANCHER!

Puis branchez une alimentation USB (5V – 2A) au module A9

Toolchain :

La toolchain contient tous les outils nécessaires à la compilation et au déploiement du code vers notre module. Téléchargez la ici : http://test.ai-thinker.com/csdk/CSDTK42.7z (la doc est ici : https://ai-thinker-open.github.io/GPRS_C_SDK_DOC/en/c-sdk/installation.html)

http://test.ai-thinker.com/csdk/CSDTK42.7z (la doc est ici : https://ai-thinker-open.github.io/GPRS_C_SDK_DOC/en/c-sdk/installation.html)

Ouvrez PowerShell en mode administrateur et placez vous dans le répertoire CSDTK (ou CSDTK42 dans mon cas), exécutez alors le script config_env_admin.bat qui va ajouter les variables d’environnement nécessaires :

./config_env_admin.bat 

SDK :

Téléchargez la SDK :https://github.com/Ai-Thinker-Open/GPRS_C_SDK/releases/tag/V2.112 (le fichier GPRS_C_SDK_V2112.7z)

Ouvrez de nouveau PowerShell en mode administrateur et placez vous dans le répertoire GPRS_C_SDK. Vous trouverez un répertoire demo contenant des exemple pour toutes les fonctionnalités!

Pour tester, nous allons compiler l’exemple first :

./build.bat demo first

Si tout se passe bien, vous verrez alors la version compilé dans le répertoire hex/first

Programmer le module :

Dans le répertoire CSDTK42\cooltools, l’utilitaire coolwatcher.exe permet de téléverser le code sur le module. Au lancement, sélectionnez le profil 8955 et précisez le port COM dans le champs lastcomport :

La première chose à faire est de sélectionner le programmateur dans le menu “Flash > Choose Flash Programmer…” et choisissez le fichier CSDTK42\cooltools\chipgen\Modem2G\toolpool\plugins\fastpf\flash_programmershost_8955_flsh_spi32m_ramrun.lod

Ensuite il faut choisir le projet compilé à téléverser en allant dans le menu “Flash > Choose LOD file…” et choisissez le fichier généré précédemment : GPRS_C_SDK\hex\trackerfirst_B2112_debug.lod (choisissez le fichier le plus lourd)

Pour lancer le téléversement, allez dans le menu “Flash > Launch fastpf with current LOD file and flash programmer”.

Si tout fonctionne bien vous devriez avoir ceci :

Cette étape n’a pas marché du premier coup pour moi, vérifiez l’ordre des branchements et surtout que les GND sont bien en commun. Si ça ne fonctionne toujours pas, cliquez sur le bouton “Restart Chip” dans coolwatcher.

Une fois l’upload terminé, allez dans le menu “Plugins > Activate Tracer” pour avoir accès à l’écran de debug. Vous devriez vois apparaître “Hello GRPS” :

Voilà! Nous avons programmé notre module! Il ne nous reste plus qu’à étudier les exemples et essayer de faire quelque chose de fun! 🙂

Librairie A6Smslib pour simplifier l’envoi d’un sms

Pour simplifier un peu le code de mon article “Envoyer des SMS avec un ESP8266 et un module A6” j’ai créé une librairie qui permet d’envoyer un sms et de voir l’état de l’envoi.

Vous pouvez le trouver sur github : https://github.com/davidtw/a6SmsLib

Exemple de code :

#include "A6SmsLib.h"

const String NUMBER = "00336XXXXXXXX";
const String MESSAGE = "whoop whoop!";

const int rx = D1;
const int tx = D2;
const int resetPin = D0;

A6SmsLib a6Sms(rx, tx, resetPin);

void statusUpdate(String state, String message)
{
  Serial.println("[statusUpdate] " + state + " : " + message);
}

void smsUpdate(String state, String message)
{
    Serial.println("[smsUpdate] " + state + " : " + message);
}

void setup()
{
    Serial.begin(9600);
    a6Sms.debug();
    a6Sms.begin();
    a6Sms.setStatusCallback(statusUpdate);
    a6Sms.setSmsCallback(smsUpdate);
    a6Sms.waitUntilReady();

    a6Sms.sms(NUMBER, MESSAGE);
}

void loop()
{
    a6Sms.loop();
}

Initialisation

Dans l’exemple j’ai configuré les entrées de la même manière que pour mon montage (D1 pour RX, D2 pour TX et D0 pour le redémarrer le module)

const int rx = D1;
const int tx = D2;
const int resetPin = D0;

A6SmsLib a6Sms(rx, tx, resetPin);

Activer le mode Debug

Active la sortie sur le port série de messages provenant de l’A6

a6Sms.debug();

Fonctions de rappel

a6Sms.setStatusCallback(statusUpdate);
a6Sms.setSmsCallback(smsUpdate);
  • setStatusCallback permet de spécifier la fonction a appeler à la mise à jour de l’état du module.
  • setSmsCallback spécifie la fonction a appeler après l’envoi d’un sms

La boucle

La fonction loop permet à la librairie de mettre à jour les états en fonction des retours du module. Il faut l’appeler à chaque itération.

L’envoi

L’envoi se fait avec la fonction SMS en précisant le numéro de téléphone du destinataire et le message.

Le tout assemblé et branché

Envoyer des SMS avec un ESP8266 et un module A6

Cet article se base sur l’article précédent (Envoyer des SMS avec un module GSM A6), je vous recommande de le lire avant afin de comprendre d’où on part ici.

Dans l’article précédent, nous avons réussi a envoyer des SMS à l’aide d’un module FTDI. Nous allons maintenant voir comment faire la même chose avec un microcontrôleur (ESP8266 dans mon cas mais ça devrait fonctionner avec n’importe quel Arduino).

Ce qu’il faut:

La même chose que pour l’article précédent, plus un microcontrôleur, moi j’ai utilisé un module Wemos D1 :

Wemos D1 mini

Je les achète directement chez le fabricant (https://wiki.wemos.cc/products:d1:d1_mini), le temps de livraison est assez long (plusieurs semaines, a un mois pour arriver en France…) mais au moins on l’a au moins chère et je n’ai jamais été déçu en terme de qualité. Pour ceux qui ne connaissent pas, ils sont top! Ils embarquent un microcontrôleur programmable, une antenne wifi, 9 entrèes numériques, une entrée analogique, un convertisseur 5V en 3,3V et 4M de mémoire. C’est largement suffisant pour faire des objets connectés, même relativement complexes.

Le câblage

J’ai fait un effort ce coup-ci 😉 et j’ai fait le schéma sous fritzing :

Schéma de câblage
Schéma de câblage

J’ai ajouté un fil entre la borne D0 du Wemos D1 mini et le RST du module qui nous permettra de le redémarrer quand on serra prêt a communiquer avec lui. Sinon il s’agit juste de l’alimenter, et de raccorder D1 et D2 respectivement aux bornes UTX et URX du module.

A cette étape, j’ai préféré faire un câblage un peu plus permanent, ça permet d’éviter les problèmes de fils cavaliers ect… Mais vous pouvez tout aussi bien tout faire sur votre breadbord. J’ai donc utilisé un perfboard et soudé le tout ensemble :

Perfboard - vue de dessus
Perfboard – vue de dessus

Perfboard - vue de dessous
Perfboard – vue de dessous (avec soudures déguelasses…)

Le tout assemblé et branché
Le tout assemblé et branché

Côté code:

Initialisation

Pour dialoguer avec notre module GSM, nous allons utiliser la communication série à travers la librairie standard SoftwareSerial:

Ensuite nous pouvons redémarrer notre module A6. Cette étape n’est probablement pas nécessaire mais permet de s’assurer de l’état du A6 au démarrage.

void resetModule() {
    digitalWrite(RESET_PIN, HIGH);
    delay(200);
    digitalWrite(RESET_PIN, LOW); 
}

void setup() {
    Serial.begin(9600);
    a6Serial.begin(115200); //le baudrate par défaut de l'A6 est 115200
    delay(500);

    pinMode(RESET_PIN, OUTPUT); //Pour redémarrer le A6, ça nous permettra de mieux controller l'état du module
    resetModule(); //On redemarre le module
}

Pour finir l’initialisation, il faut attendre que le module soit prêt et connecté au réseau, puis le passer en mode SMS :

void waitUntilReady()
{
  Serial.println("En attente du réseau");
  unsigned long startTime = millis();
  while(state == "initing" || state == "sms_mode") {  
    if (a6Serial.available()) {
      String recievedA6 = a6Serial.readString();
      Serial.println(recievedA6);
      if(state == "initing" && recievedA6.indexOf("+CREG: 5") >= 0) {
        Serial.println("Mode sms");
        state = "sms_mode";
        delay(2000);
        a6Serial.println("AT+CMGF=1");  
      } else if(state == "sms_mode" && recievedA6.indexOf("OK") >= 0) {
        state = "ready";
        Serial.println("Tout est prêt!");
      }
    }
    yield(); // redonne la main à l'esp8266 temporairement pour qu'il maintienne la connetion au wifi
  }
}

Envoyer un sms

Comme vu dans l’article précédent, l’envoi d’un sms se fait en envoyant la commande AT

suivi du message, puis Ctrl-Z pour envoyer :

void sendSms(String number, String message) {
  if(state == "ready") {
    Serial.println("Sending \"" + message + "\" to " + number);
    a6Serial.print("AT+CMGS=\"");
    a6Serial.print(number);
    a6Serial.write(0x22);
    a6Serial.write(0x0D);  // Retour chariot en hexadecimal
    a6Serial.write(0x0A);  // Nouvelle ligne en hexadecimal
    delay(2000);
    a6Serial.print(message);
    delay(500);
    a6Serial.println(char(26));// Control-Z en hexadecimal
  }
}

Pour l’exemple j’envoi un SMS en envoyant la commande sendSms à l’Esp8266 par l’objet Serial :

#define PHONE_NUMBER "+336XXXXXXXX"
#define MESSAGE "Whoop whoop"

void loop() {
  if(Serial.available()) {
    String received = Serial.readString();
    received.trim();
    if(state == "ready") {
      if(received == "sendSms") {
        sendSms(PHONE_NUMBER , MESSAGE );
      }
    }
  }
}

Ce qui donne :

Résultat de l'envoi d'un SMS
Résultat de l’envoi d’un SMS

Le code complet :

#include <Arduino.h>
#include <SoftwareSerial.h>

#define RX_PIN D1 // Fil jaune
#define TX_PIN D2 // Fil orange
#define RESET_PIN D0 // Fil jaune

#define PHONE_NUMBER "+336XXXXXXXXX"
#define MESSAGE "Whoop whoop"

SoftwareSerial a6Serial(RX_PIN, TX_PIN);
String state = "initing";

void resetModule() {
    digitalWrite(RESET_PIN, HIGH);
    delay(200);
    digitalWrite(RESET_PIN, LOW); 
}

void waitUntilReady()
{
  Serial.println("En attente du réseau");
  while(state == "initing" || state == "sms_mode") {  
    if (a6Serial.available()) {
      String recievedA6 = a6Serial.readString();
      Serial.println(recievedA6);
      if(state == "initing" && recievedA6.indexOf("+CREG: 5") >= 0) {
        Serial.println("Mode sms");
        state = "sms_mode";
        delay(2000);
        a6Serial.println("AT+CMGF=1");  
      } else if(state == "sms_mode" && recievedA6.indexOf("OK") >= 0) {
        state = "ready";
        Serial.println("Tout est prêt!");
      }
    }
    yield();
  }
}

void sendSms(String number, String message) {
  if(state == "ready") {
    Serial.println("Sending \"" + message + "\" to " + number);
    a6Serial.print("AT+CMGS=\"");
    a6Serial.print(number);
    a6Serial.write(0x22);
    a6Serial.write(0x0D);  // Retour chariot en hexadecimal
    a6Serial.write(0x0A);  // Nouvelle ligne en hexadecimal
    delay(2000);
    a6Serial.print(message);
    delay(500);
    a6Serial.println(char(26));// Control-Z en hexadecimal
  }
}

void setup() {
    Serial.begin(9600);
    a6Serial.begin(115200); //le baudrate par défaut de l'A6 est 115200
    delay(500);

    pinMode(RESET_PIN, OUTPUT); //Pour redémarrer le A6, ça nous permettra de mieux controller l'état du module
    resetModule(); //On redemarre le module
    waitUntilReady(); // On attend d'être connecté au réseau GSM
}

void loop() {
  if(Serial.available()) {
    String received = Serial.readString();
    received.trim();
    if(state == "ready") {
      if(received == "sendSms") {
        sendSms(PHONE_NUMBER, MESSAGE);
      }
    }
  }
  if (a6Serial.available()) {
      String recievedA6 = a6Serial.readString();
      Serial.println("[A6] " + recievedA6);
  }
}

Conclusion

Nous voila avec un petit module qui nous permet d’envoyer des sms, il ne reste plus qu’à en faire un objet connecté (enfin, encore plus connecté!)

Envoyer des SMS avec un module GSM A6

AI Thinker, les fabricants de mes MCU préférés, les ESP8266 ont sorti il y a quelques temps déjà le module GSM A6 permettant de se connecter au réseau GSM / GPRS et d’envoyer des SMS, se connecter à internet et même d’émettre des appels!

J’ai eu l’idée de me faire un petit appareil connecté qui recevra des ordres par MQTT et enverra des SMS, ce qui me permettra de recevoir un sms facilement à chaque fois qu’un de mes capteurs remontrons une info importante. Cet article est la première étape, je vais en écrire d’autres au fur et à mesure que le projet avance.

Ce qu’il faut:

  • Module GSM/GRPS A6 mini Un module A6 :  (ici il s’agit d’un modue A6 mini disponible sur ebay, aliexpress, ect.. pour 5 à 10€)
  • Carte SIM Une carte SIM, j’ai pris une carte free à 2€/mois (si votre box est chez free elle est même gratuite)
  • Breadboard et fils de cavalier Quelques fils de cavalier et un breadboard
  • module FTDI Un module FTDI ‘entre 2 et 5€ sur Ebay ou aliexpress
  • PCB micro USB Une PCB avec prise USB pour alimenter le tout et un chargeur de téléphone pour alimenter tout ça.
  • Alimentation Une alimention assez puissante (ici j’ai recyclé une alim qui me servait pour un raspberry de 5V/2A). L’envoi de SMS demande pas mal de courant au moment de l’envoi.
  • CoolTerm Un ordinateur sous Windows avec CoolTerm (ça se fait très bien sous Mac ou linux mais je n’en ai pas sous la main)

Le câblage

Schéma de câblage du module A6 avec un FTDI
Schéma de câblage du module A6 avec un FTDI

Comme vous pouvez le constater, j’ai réuni tous mes talents de graphiste pour pondre ce schéma très très moche!!

L’idée est d’alimenter le module avec notre chargeur de téléphone, de mettre les les neutres du module A6 et de l’FTDI en commun puis de brancher le TX du module A6 au RX de du FTDI et vice et versa.

le cablage fini
Le montage fini et branché

Côté PC

Normalement CoolTerm arrivera a trouver tout seul le port COM sur lequel est branché votre FTDI. Sinon vous pourvez le trouver dans le gestionnaire de périphériques :

Gestionnaires de périphériques
Gestionnaires de périphériques

Dans coolTerm, réglez le baudrate à 115200 et cliquez sur Connect. Ca prend quelques secondes mais vous devriez voir apparaître des les retours du A6 qui ressemblent à ça :

connexion au réseau GSM

+CREG: 5 signifie que le module est connecté au réseau et est prêt a recevoir et envoyer des sms!

Si vous n’avez aucun retour du module, vérifiez que le branchement est bon, surtout au niveau des rx/tx, je me suis fait avoir…

Envoi du SMS

Pour envoyer une commande au module, allez dans Connection -> Send String ou faites Ctrl-T sous windows. La commande AT (pour Attention) suivi d’un retour à la ligne vous renverra l’état du module :

Envoi de la commande ATRécupération de l'état

Normalement, le module devrait répondre “OK”, mais il m’est arrivé d’avoir des erreurs CME 58, je crois que ça veut dire qu’il a temporairement perdu le signal, en réessayant la commande AT, ça se mettait a fonctionner.

Ensuite pour passer le module en mode SMS, envoyez :

AT+CMGF=1

toujours suivi d’un retour à la ligne.

passage en mode sms

Et enfin pour envoyer le message :

AT+CMGS="003361234567"

(en remplaçant bien sur par le numéro auquel vous voulez envoyer). Il vous demandera ensuite d’entrer votre message, fermez la boite de dialogue et dans coolTerm faites Ctrl-z pour envoyer le message :

Retour série après envoi du sms

Attendez quelques secondes et consultez votre téléphone!

Pièges:

J’ai eu quelques problèmes au début pour communiquer avec le module, il faut bien vérifier tous les branchements (mes fils de cavaliers de chine ne sont pas d’une qualité extraordinaire…) et j’utilisais une rallonge USB qui ne marchait pas très bien non plus.

Voici un document qui m’a aidé de MultiTech Systems qui reprend les commandes AT de base et qui donne la signification d’erreurs : GSM Developer Guide – GSM AT Commands – Rev A

Conclusion

Une fois les branchements correctement faits et que le module répond, il suffit de 3 lignes pour envoyer un Sms! Dans un prochain article, je montrerais comment envoyer un message depuis un arduino ou encore mieux, un ESP8266!