ESP32 : Envoyer un SMS avec Twilio

Introduction

Dans ce tutoriel, nous allons apprendre à utiliser l’API de Twilio pour envoyer un SMS depuis l’ESP32, en utilisant le noyau Arduino.

Twilio est une société de plateforme de communication Cloud en tant que service qui, entre autres fonctionnalités, propose une API permettant d’envoyer des SMS par programmation [1]. Bien qu’il s’agisse d’un service payant, Twilio propose un compte d’essai que nous pouvons utiliser pour tester les fonctionnalités offertes par sa plateforme. Nous supposons l’utilisation du compte d’essai pour ce didacticiel.

Vous pouvez consulter la documentation de l’API SMS ici .

Bien que la section code détaille la plupart des étapes que nous allons suivre pour pouvoir accéder à l’API de Twilio et envoyer le SMS, vous pouvez consulter ces précédents articles ESP32 pour plus de détails sur certaines parties du code :

  • Envoi de requêtes HTTP POST : explique les bases sur la façon d’effectuer des requêtes HTTP POST à ​​partir de l’ESP32, telles que l’initialisation de la requête, l’ajout d’en-têtes et l’exécution de la requête proprement dite.
  • Envoi de requêtes HTTPS : explique comment effectuer des requêtes HTTP S à partir de l’ESP32 et comment fournir un certificat CA. Bien que, par souci de simplicité, nous n’allons utiliser aucun certificat dans notre code, c’est une bonne idée d’en fournir un dans un scénario réel, pour des raisons de sécurité.
  • Ajout d’une authentification de base à une requête HTTP : explique comment ajouter une authentification de base lors de l’exécution d’une requête HTTP depuis l’ESP32. Dans le didacticiel mentionné, nous construisons nous-mêmes l’en-tête, ce qui donne une vue plus détaillée de ce qui se fait sous le capot. Ici, par souci de simplicité, nous utiliserons une méthode du noyau Arduino qui reçoit uniquement le nom d’utilisateur et le mot de passe et s’occupe des détails.

Veuillez noter que nous n’utiliserons aucune bibliothèque Twilio pour prendre en charge les détails HTTP. Cela signifie que nous allons construire nous-mêmes la requête HTTP (ce qui est très simple, comme nous le verrons ci-dessous). Néanmoins, au moment d’écrire ces lignes, j’ai trouvé cette bibliothèque qui nous cache ces détails. Bien que je ne l’ai pas testé et que je ne puisse pas confirmer qu’il fonctionne comme prévu, je le laisse ici comme référence pour ceux qui pourraient être intéressés à l’essayer.

Les tests présentés ci-dessous ont été effectués sur une  carte ESP32-E FireBeetle  de  DFRobot . La version principale d’Arduino utilisée était  la 2.0.0  et la version de l’IDE Arduino était  la 1.8.15 , fonctionnant sous Windows  8.1 . Le code a également été testé sur  Platformio et les captures d’écran des tests présentés ci-dessous ont été prises à partir de cette plateforme.

Obtenir les informations d’identification du compte Twilio

Nous n’allons pas aborder ici tous les détails sur la façon de créer un compte d’essai ou ses limitations, car celles-ci peuvent changer avec le temps. Alors, veuillez suivre le guide de Twilio , car il détaille toutes les étapes nécessaires.

Au moment de la rédaction, nous avons besoin d’une adresse e-mail valide pour nous inscrire sur la plateforme et nous devons valider un numéro de téléphone personnel, car nous ne sommes autorisés à envoyer des SMS de test qu’à ce numéro validé lorsque nous utilisons le compte d’essai. Nous allons également mettre en place un service de messagerie, ce qui peut être fait gratuitement au moment de la rédaction.

Afin de pouvoir envoyer des SMS, nous aurons besoin des informations suivantes, qui peuvent être obtenues sur les pages du compte Twilio :

  • Numéro de compte (SID)
  • Jeton d’authentification API
  • SID du service de messagerie

Pour obtenir le numéro de compte et le jeton d’authentification, nous pouvons naviguer dans le menu de gauche (après nous être connecté à Twilio), sur le séparateur « Messagerie », sur l’entrée « Get Set Up ». Là, nous pouvons obtenir à la fois le SID du compte et le jeton d’authentification, comme indiqué en vert sur la figure 1.

Menu avec l'ID de compte Twilio et le jeton API.
Figure 1 – Menu avec le SID du compte Twilio et le jeton API.

Pour obtenir l’ID du service de messagerie, nous pouvons cliquer sur l’option « Gérer et afficher tous vos services de messagerie », également mise en évidence sur la figure 1. Une fois arrivé à la page correspondante, vous devriez voir un tableau avec les services de messagerie dont vous disposez, et un des colonnes contient le SID correspondant, comme indiqué sur la figure 2.

Si vous ne voyez aucun service de messagerie sur le tableau, vous devez d’abord en créer un.

Menu avec les identifiants des services de messagerie.
Figure 2 – Menu avec les identifiants des services de messagerie.

Après avoir obtenu ces 3 informations d’identification, nous disposons de toutes les informations dont nous avons besoin sur notre compte Twilio pour démarrer l’envoi de SMS par programmation depuis l’ESP32.

Avant de passer à l’ESP32, nous pouvons également essayer la fonctionnalité d’envoi de SMS depuis le menu « Envoyer un SMS », comme le montre la figure 3. Il affiche même des exemples de code pour différents langages de programmation (en utilisant le SDK de Twilio) et en utilisant curl . Il est recommandé de tester d’abord en utilisant cette méthode, pour s’assurer que le téléphone portable que nous avons enregistré est accessible, avant d’essayer d’exécuter le code ESP32.

Menu pour tester l'envoi d'un SMS.
Figure 3 – Menu pour tester l’envoi d’un SMS.

Veuillez noter que toutes les interfaces utilisateur présentées précédemment peuvent avoir changé au moment où vous consultez cet article.

Le code

Nous commencerons notre code par les inclusions de la bibliothèque. Nous aurons besoin des bibliothèques suivantes :

  • WiFi.h : comme d’habitude, nous devons inclure la lib WiFi.h pour pouvoir connecter l’ESP32 à un réseau WiFi, afin qu’il puisse ensuite accéder à Internet.
  • HTTPClient.h : expose une interface facile à utiliser pour effectuer des requêtes HTTP.
  • sstream : permet d’utiliser la classe stringstream , que nous utiliserons pour pouvoir concaténer des chaînes de manière très simple.
#include <WiFi.h>
#include <HTTPClient.h>
#include <sstream>

Nous aurons également besoin des informations d’identification du réseau WiFi (nom et mot de passe), afin de pouvoir connecter l’ESP32 à ce réseau. N’oubliez pas de remplacer les espaces réservés que j’utilise ci-dessous par les informations d’identification réelles de votre propre réseau.

const char* ssid = "yourNetworkName";
const char* password =  "yourNetworkName";

Nous allons maintenant définir 4 espaces réservés supplémentaires pour les informations nécessaires à l’envoi du SMS (3 d’entre eux sont ceux que nous avons obtenus dans la section précédente) :

  • Service de messagerie SID : L’identifiant du service de messagerie.
  • Numéro de téléphone de destination : Le numéro auquel nous souhaitons envoyer un SMS. Ce numéro doit inclure le code du pays . Par exemple, dans mon cas, la destination est un numéro de téléphone portugais, ce qui signifie qu’elle doit commencer par « +351 ». N’oubliez pas que ce numéro doit avoir été validé au préalable sur la plateforme Twilio.
  • Numéro de compte (SID) : numéro du compte. Il est nécessaire à la fois pour l’URL de l’API mais également pour l’authentification.
  • Mot de passe (clé API) : La clé API utilisée comme mot de passe lors de l’authentification.
const char * messagingServiceSid = "yourMessagingServiceId";
const char * to = "destinationPhoneNumber";
const char * accountNr = "yourAccountNr;
const char * twilioPassword = "yourApiKey";

Passant à la configuration Arduino, nous commencerons par ouvrir une connexion série, afin de pouvoir ensuite afficher des messages d’information.

Serial.begin(115200);

Après cela, nous connecterons l’ESP32 au réseau WiFi, en utilisant les informations d’identification fournies précédemment.

WiFi.begin(ssid, password); 
  
while (WiFi.status() != WL_CONNECTED) {
  delay(1000);
  Serial.println("Connecting to WiFi..");
}

Nous allons encapsuler la logique réelle d’envoi de SMS dans une fonction appelée sendSMS , qui reçoit en entrée une chaîne avec le corps du message à envoyer au numéro de destination. Nous vérifierons l’implémentation de la fonction ci-dessous, mais nous supposerons qu’elle renvoie un booléen indiquant si la procédure a réussi ou non, pour vérifier les erreurs.

bool result = sendSMS("Test SMS from ESP32");
 
if(result){
  Serial.println("\nSMS sent");
}else{
  Serial.println("\nSMS failed");
}

La configuration complète d’Arduino est disponible dans l’extrait de code ci-dessous.

void setup() {
  
  Serial.begin(115200);
 
  WiFi.begin(ssid, password); 
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }
  
  Serial.println("Connected to the WiFi network");
 
  bool result = sendSMS("Test SMS from ESP32");
 
  if(result){
    Serial.println("\nSMS sent");
  }else{
    Serial.println("\nSMS failed");
  }
 
}

Puisque nous utilisons le compte gratuit de Twilio, dont le solde est limité, nous enverrons le message une seule fois dans la configuration Arduino, ce qui signifie que nous laisserons la boucle principale Arduino vide.

void loop() { }

Pour finaliser, nous vérifierons l’implémentation de la fonction sendSMS , qui reçoit une chaîne en entrée et renvoie un booléen indiquant si le processus s’est terminé avec succès.

bool sendSMS(const char * body){
   // Send SMS using Twilio's API
}

La première chose que nous ferons est de créer l’URL de l’API, qui a le numéro de compte comme paramètre de route. Naturellement, nous aurions pu le coder en dur ici, mais il sera plus facile de le modifier à l’avenir si nous avons simplement cette valeur comme variable en haut de notre code.

Fondamentalement, l’URL est composée de plusieurs parties que nous souhaitons concaténer. Nous utiliserons un stringstream et l’ opérateur << pour construire la chaîne finale avec l’URL complète.

L’URL de base est « https://api.twilio.com/2010-04-01 » [2]. Puisque l’envoi d’un SMS sera lié à notre compte, nous avons alors la ressource Comptes , suivie de l’ID de notre compte (que nous avons stocké dans une variable globale). Enfin, nous devons créer une ressource Message [3]. Ainsi, l’URL complète est la suivante [3] :

https://api.twilio.com/2010-04-01/Accounts/{yourAccountSid}/Message

Notez que l’API fonctionne uniquement sur HTTPS pour garantir la confidentialité des données [2]. Pour notre cas de test, nous ne fournissons aucun certificat à valider par notre client HTTP, mais dans une application réelle, vous devez l’utiliser.

En résumé, le code permettant de créer une chaîne avec l’URL finale à partir de ses parties est présenté ci-dessous.

std::stringstream url;
url << "https://api.twilio.com/2010-04-01/Accounts/" << accountNr <<"/Messages";

De même, nous allons construire la charge utile du corps sous forme de chaîne, en utilisant à nouveau la classe stringstream . Dans notre cas, nous devons spécifier les paramètres suivants dans le corps :

  • Numéro de destination : Le numéro de téléphone de destination, que nous avons dans une variable globale. En mode essai, ce numéro doit avoir été vérifié [3]. Dans le corps, le paramètre est appelé To .
  • Messaging Service SID : L’identifiant du service de messagerie, que nous avons également dans une variable globale. Dans le corps, le paramètre est appelé MessagingServiceSid .
  • Contenu du SMS : le contenu réel du SMS, qui doit être la chaîne que nous avons reçue en entrée de notre fonction sendSMS . Dans le corps, le paramètre s’appelle Body .

Le format de ce corps doit être codé sous forme d’URL . Ainsi, nous construirons le corps à partir de ses parties conformément à ce format.

std::stringstream urlEncodedBody;
urlEncodedBody << "MessagingServiceSid=" << messagingServiceSid << "&To=" << to << "&Body=" << body;

Pour confirmer que nous obtenons le format correct pour l’URL et le corps, nous imprimerons les valeurs résultantes sur le port série. Naturellement, cela est fait à des fins de débogage et, sur une application finale, nous n’aurions pas besoin de le faire.

Pour obtenir le contenu d’un stringstream sous la forme d’un std::string , il suffit d’appeler la méthode str , qui ne prend aucun argument. Étant donné que les méthodes d’impression série ne prennent pas en charge la classe std::string , nous devons ensuite appeler la méthode c_str pour obtenir la version de style C de la chaîne.

Serial.print("\nURL: ");
Serial.println(url.str().c_str());
Serial.print("Encoded body: ");
Serial.println(urlEncodedBody.str().c_str());

Maintenant que nous avons à la fois l’URL de destination et le corps, nous allons commencer à créer notre requête HTTP. Nous commençons par créer un objet de classe HTTPClient .

HTTPClient http;

Ensuite, pour initialiser la requête et spécifier l’URL de destination, nous appelons la méthode start sur notre objet HTTPClient , en passant en entrée l’URL. Encore une fois, nous appelons la méthode str pour obtenir le std::string correspondant puis nous appelons la méthode c_str .

Notez que si vous souhaitez ajouter un certificat CA pour valider la demande, vous pouvez utiliser cette version surchargée de la méthode Begin.

http.begin(url.str().c_str());

Nous devons également spécifier quel est le type de contenu du corps en définissant l’en-tête correspondant, afin que le serveur auquel nous arrivons sache comment interpréter les données du corps. Pour ajouter un en-tête à la requête, on appelle simplement la méthode addHeader , en passant en première entrée le nom de l’en-tête et en deuxième la valeur de l’en-tête.

http.addHeader("Content-Type", "application/x-www-form-urlencoded");

Les requêtes adressées à l’API doivent inclure l’authentification de base , où le nom d’utilisateur est le numéro de compte (SID) et le mot de passe est la clé API [2]. Pour ajouter les informations d’identification d’autorisation, nous devons appeler la méthode setAuthorization sur notre objet HTTPClient , en passant en entrée le numéro de compte et la clé API (tous deux stockés dans les informations d’identification globales).

http.setAuthorization(accountNr, twilioPassword);

Comme déjà mentionné, nous allons créer une ressource Message lors de l’appel de l’API pour envoyer le SMS [3]. A ce titre, nous utiliserons une méthode HTTP POST. Pour ce faire, nous devons simplement appeler la méthode POST sur notre objet HTTPClient , en passant en entrée le corps encodé en URL que nous avons créé précédemment.

En sortie, cette méthode renverra le code de réponse HTTP (au cas où la requête serait exécutée avec succès). Cependant, si cette valeur est inférieure à 0, alors une erreur de connexion s’est produite. Nous stockerons ce résultat dans une variable pour vérifier les erreurs.

inthttpCode =http.POST(urlEncodedBody.str().c_str()); 

Dans le cas où la réponse est un code HTTP standard (supérieur à zéro), nous imprimerons ce code ainsi que le corps de la réponse. Nous imprimons le corps de la réponse à des fins de débogage car si, par exemple, nous avons transmis un paramètre de manière incorrecte, nous obtiendrons un code de réponse 400 que nous devrons analyser et résoudre.

Dans le cas où le code renvoyé est inférieur à zéro, nous l’imprimerons simplement sur le port série. La liste des erreurs possibles liées à la connexion peut être analysée ici .

if (httpCode > 0) {
 
  String payload = http.getString();
 
  Serial.print("\nHTTP code: ");
  Serial.println(httpCode);
 
  Serial.print("\nResponse: ");
  Serial.println(payload);
}
 
else {
  Serial.println("Error on HTTP request:");
  Serial.println(httpCode);
}

Après avoir terminé la requête, nous devons appeler la méthode end sur notre objet HTTPClient , pour libérer les ressources.

http.end();

Enfin, pour confirmer si le processus a réussi ou non, il faut tenir compte du fait que l’API renvoie le code HTTP 201 lorsque la demande a été correctement reçue et traitée, indiquant ainsi que le SMS sera envoyé. Nous comparerons cette valeur à ce que nous avons reçu en réponse HTTP de l’appel API, afin de pouvoir renvoyer un booléen en sortie de la fonction sendSMS .

returnhttpCode ==201;

La fonction sendSMS complète est présentée ci-dessous.

bool sendSMS(const char * body){
 
  std::stringstream url;
  url << "https://api.twilio.com/2010-04-01/Accounts/" << accountNr <<"/Messages";
 
  std::stringstream urlEncodedBody;
  urlEncodedBody << "MessagingServiceSid=" << messagingServiceSid << "&To=" << to << "&Body=" << body;
 
  Serial.print("\nURL: ");
  Serial.println(url.str().c_str());
  Serial.print("Encoded body: ");
  Serial.println(urlEncodedBody.str().c_str());
   
 
  HTTPClient http;
 
  http.begin(url.str().c_str());
  http.addHeader("Content-Type", "application/x-www-form-urlencoded");
  http.setAuthorization(accountNr, twilioPassword);
   
  int httpCode = http.POST(urlEncodedBody.str().c_str());                                               
  
  if (httpCode > 0) {
 
      String payload = http.getString();
 
      Serial.print("\nHTTP code: ");
      Serial.println(httpCode);
 
      Serial.print("\nResponse: ");
      Serial.println(payload);
    }
 
  else {
    Serial.println("Error on HTTP request:");
    Serial.println(httpCode);
  }
 
  http.end();
 
  return httpCode == 201;
 
}

Le code complet est affiché ci-dessous.

#include <WiFi.h>
#include <HTTPClient.h>
#include <sstream>
 
const char* ssid = "yourNetworkName";
const char* password =  "yourNetworkName";
 
const char * messagingServiceSid = "yourMessagingServiceId";
const char * to = "destinationPhoneNumber";
const char * accountNr = "yourAccountNr;
const char * twilioPassword = "yourApiKey";
 
bool sendSMS(const char * body){
 
  std::stringstream url;
  url << "https://api.twilio.com/2010-04-01/Accounts/" << accountNr <<"/Messages";
 
  std::stringstream urlEncodedBody;
  urlEncodedBody << "MessagingServiceSid=" << messagingServiceSid << "&To=" << to << "&Body=" << body;
 
  Serial.print("\nURL: ");
  Serial.println(url.str().c_str());
  Serial.print("Encoded body: ");
  Serial.println(urlEncodedBody.str().c_str());
   
 
  HTTPClient http;
 
  http.begin(url.str().c_str());
  http.addHeader("Content-Type", "application/x-www-form-urlencoded");
  http.setAuthorization(accountNr, twilioPassword);
   
  int httpCode = http.POST(urlEncodedBody.str().c_str());                                               
  
  if (httpCode > 0) {
 
      String payload = http.getString();
 
      Serial.print("\nHTTP code: ");
      Serial.println(httpCode);
 
      Serial.print("\nResponse: ");
      Serial.println(payload);
    }
 
  else {
    Serial.println("Error on HTTP request:");
    Serial.println(httpCode);
  }
 
  http.end();
 
  return httpCode == 201;
 
}
 
void setup() {
  
  Serial.begin(115200);
 
  WiFi.begin(ssid, password); 
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }
  
  Serial.println("Connected to the WiFi network");
 
  bool result = sendSMS("Test SMS from ESP32");
 
  if(result){
    Serial.println("\nSMS sent");
  }else{
    Serial.println("\nSMS failed");
  }
 
}
  
 
void loop() { }

Tester le code

Pour tester le code, compilez-le et téléchargez-le sur votre appareil à l’aide d’un outil de votre choix (Arduino IDE, Platformio). Assurez-vous de remplacer tous les espaces réservés du code ci-dessus par les valeurs réelles de votre compte.

Une fois la procédure terminée, ouvrez un outil de surveillance série. Vous devriez voir un résultat similaire à la figure 4 ci-dessous, en cas de succès. J’ai caché mes informations d’identification personnelles ainsi que la réponse (car elle renvoie une partie du contenu que nous avons envoyé dans le corps, mais ce qui reste devrait illustrer ce qui est attendu).

Nous pouvons voir à la fois l’URL et le corps construits comme prévu et que le code de réponse HTTP est 201. De plus, nous avons obtenu la charge utile au format XML. En cas d’erreur (ex : 400 due à des paramètres incorrects), ce payload est très utile puisqu’il identifie le problème. De plus, nous pouvons voir par le message « SMS envoyé » que nous avons pu afficher correctement le résultat booléen de la fonction sendSMS.

Contenu imprimé sur le port série après l'envoi réussi d'un SMS à l'aide de l'API de Twilio.
Figure 4 – Contenu imprimé sur le port série après l’envoi réussi d’un SMS à l’aide de l’API de Twilio.

Sur votre téléphone portable, vous devriez recevoir un message comme celui illustré dans la figure 5. Comme on peut le voir, il inclut le texte « Envoyé depuis votre compte d’essai Twilio », qui est envoyé lors de l’utilisation du compte d’essai. De plus, nous pouvons voir le corps du texte que nous avons défini dans notre code : « Test SMS from ESP32 ».

SMS reçu sur le téléphone de destination, envoyé depuis Twilio.
Figure 5 – SMS reçu sur le téléphone de destination.

Les références

[1] https://en.wikipedia.org/wiki/Twilio

[2] https://www.twilio.com/docs/sms/api

[3] https://www.twilio.com/docs/sms/api/message-resource#create-a-message-resource

A lire également

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *