Publication LoRaWAN de mesures environnementales avec un module LoRa-E5
Ce tutoriel explique comment mettre en œuvre une publication LoRaWAN sur The Things Network (TTN) avec une intégration TagoIO en utilisant l’environnement STM32duino pour un module Grove LoRa-E5 côté objet.
Pour en apprendre un peu plus sur LoRa et LoRaWAN, vous pouvez consulter cette page et pour vraiment tout comprendre lisez ce document de Sylvain Montagny (Université de Savoie - Mont Blanc). Notre sketch Arduino pour poster des mesures est d’ailleurs directement construit à partir de la bibliothèque développée et partagée par M. Montagny.
Matériel requis et montage
Notre système connecté sera constitué des composants suivants :
- Pour la communication LoRa / LoRaWAN côté objet, nous avons choisi un module Grove LoRa-E5 de Seeed studio, basé sur un système sur puce (SoC) STM32WLE5JC de STMicroelectronics.
- Une carte d’extension de base Grove avec son commutateur d’alimentation en position 3.3V
- Une carte NUCLEO-L476
- Un module Grove BME280
- Un câble Grove - Dupont mâle.
- Pour la passerelle LoRaWAN, nous avons choisi la The Things Indoor Gateway (TTIG).
Un module Grove LoRa-E5 | Une passerelle LoRa-WiFi TTIG |
---|---|
Crédit image : Seeed Studio | Crédit image : The Things Network |
Placez la carte d’extension Grove sur la carte NUCLEO et connectez-y le module BME280 (sur une fiche grove I2C) et le module LoRa-E5. La seule difficulté consiste à connecter correctement le module LoRa-E5 à l’UART4 de la carte NUCLEO-L476RG, avec le câble Grove - Dupont mâle, conformément aux indications données sur cette page :
Broche du module LoRa-E5 | Broche (Arduino) de la NUCLEO-L476RG |
---|---|
GND | GND |
VCC | 3V3 |
RX | A0 (TX de l’UART4) |
TX | A1 (RX de l’UART4) |
Première étape : Obtention du DevEUI du module LoRa-E5
Le module Grove LoRa-E5 est piloté à l’aide de “commandes AT”. Ceci signifie que Seeed Studio l’a programmé avec un firmware qui reçoit des commandes en mode texte et y répond, également par du texte, au moyen du protocole série. La même stratégie est souvent utilisée pour piloter des modules GPS, Wi-Fi ou Bluetooth. La documentation des commandes AT du module est disponible ici.
Dans cette première partie, nous allons utiliser une commande AT pour interroger le module et obtenir son DevEUI, un identifiant unique encodé sur 64 bits qui nous servira pour son enregistrement sur le réseau LoRaWAN de TTN.
Bibliothèque(s) requise(s)
Aucune bibliothèque n’est nécessaire pour cet exemple, le sketch qui suit est suffisant.
Le sketch Arduino
Le sketch pour cet exemple (et tous les autres) peut être téléchargé en cliquant ici. Vous le trouverez dans le dossier “\LoRaWAN - Publication LoRa-E5\LoRa_E5_AT”.
Lancez l’IDE Arduino, ouvrez un nouveau sketch vide et copiez-y le code qui suit :
void setup() {
// Démarrage du port série du ST-LINK
Serial.begin(STLK_BDRATE);
// Démarrage du port série du module LoRa-E5
LoRa.begin(LORA_BDRATE);
Serial.println("Setup completed !");
}
void loop() {
// Lecture des commandes en provenance du terminal série Arduino
// Envoi de ces commandes au module LoRa-E5
while (Serial.available() > 0) {
LoRa.write(Serial.read());
}
// Lecture des réponses du module LoRa-E5
// Ecriture de ces réponses sur le terminal série Arduino
while (LoRa.available() > 0) {
Serial.write(LoRa.read());
}
}
On remarquera que le baudrate du module LoRa-E5 est par défaut fixé à 9600. Cela peut être modifié par une autre commande AT, mais nous ne vous conseillons pas de le faire sans une bonne raison.
Après avoir vérifié que l’IDE Arduino est correctement configurée, notamment qu’elle est connectée au port COM attribué au ST-LINK de votre carte (sous Windows), cliquez sur “Téléverser”.
Utilisation du sketch Arduino
La première étape consiste à vous assurer que le module est correctement connecté. Tapez AT
dans la boite de saisie du terminal série de l’IDE Arduino, qui doit par ailleurs être paramétré en “Both NL & CR” et “9600 bauds”.
Sa réponse, +AT: OK
confirmera que tout va bien.
Ensuite, tapez AT+ID et ENTER, vous devriez obtenir une réponse de cette forme :
+ID: DevAddr, 44:10:BA:4A
+ID: DevEui, 2C:F7:F1:20:44:10:BA:4A
+ID: AppEui, 00:00:00:00:00:00:00:00
Notre module renvoie trois clefs dont DevEUI, qui servira à le connecter à un futur réseau LoRaWAN. Elle sera bien sûr différente pour votre module puisqu’il s’agit d’un identifiant unique. Notez la valeur de DevEui, vous en aurez besoin dans la deuxième étape ci-après. L’autre clef importante est AppEui, qui ne restera pas “à zéro” et sera fournie par TTN à l’issue de la deuxième étape. Pour en savoir plus sur la signification de ces clefs, vous pouvez consulter cette page.
Deuxième étape :
- Création d’un réseau LoRaWAN privé avec la passerelle TTIG pour un module LoRa-E5
- Création d’un lien entre TTN et l’intégration TagoIO
Pour la configuration de la passerelle et de tous les services permettant de recueillir les mesures du module loRa-E5 d’abord sur TTN puis sur TagoIO, nous vous renvoyons à ce tutoriel. Pour aller jusqu’au bout, vous aurez besoin de la clef DevEui obtenue ci-avant, à la première étape.
Troisième étape : Connexion au réseau LoRaWAN et publication des mesures sur TTN et TagoIO
Nous allons à présent nous concentrer sur le sketch Arduino qui se connectera à TTN et postera les mesures de température, d’humidité et de pression du capteur BME280 dans un format hexadécimal compact approprié pour les trames LoRaWAN. Ceci signifie que nous devrons également configurer sur notre compte TagoIO un script en langage NodeJS pour extraire ces mesures des trames LoRaWAN et les “décoder” avant de les afficher dans un dashboard.
Bibliothèque(s) requise(s)
Ce sketch utilise trois bibliothèques :
-
La bibliothèque LoRaWAN-Seeed-Grove-Wio-E5, dans sa révision 3.0.0, par Sylvain Montagny. Elle permet de piloter le module LoRa-E5 avec des commandes AT. Notre sketch reprend la quasi totalité du code de l’exemple LoRWAN_Class_A.ino distribué avec cette bibliothèque.
-
La bibliothèque GyverBME280 permettant de réaliser des mesures avec le module Grove BME280 en exploitant son mode basse consommation.
-
La bibliothèque STM32duino Low Power pour mettre en sommeil le MCU STM32L476RG de la carte NUCLEO entre deux publications LoRaWAN.
Le sketch Arduino
Le sketch pour cet exemple (et tous les autres) peut être téléchargé en cliquant ici. Vous le trouverez dans le dossier “\LoRaWAN - Publication LoRa-E5\LoRa_E5_Publish”.
Remarque importante
La fonction void measure(void)
utilisée dans le sketch fait appel à une autre fonction, printf()
pour afficher les mesures des capteurs environnementaux , de type float
. Cette opération nécessite une configuration préalable pour se dérouler correctement : dans l’IDE Arduino, vous devez cocher l’option “Newlib Nano + Float printf” du menu “Outils/C Runtime Library”.
Ceci, fait, lancez l’IDE Arduino, ouvrez un nouveau sketch vide et copiez-y le code qui suit :
//*******************************************************************************************
// Connexion d'un module LoRa-E5 à un réseau LoRaWAN privé sur TTN, préalablement configuré.
// Publication de données de température, humidité et pression sur TTN dans un format
// hexadécimal qui devra ensuite être "décodé" par un parser de payloads sur TagoIO.
// La bibliothèque pour le module LoRa-E5 utilisée est celle de Sylvain Montagny
// dans sa révision 3.0.0.
// Voir la page README sur https://github.com/SylvainMontagny/LoRaE5, le code exemple
// utilisé (recopié presque tel quel) est "LoRWAN_Class_A.ino".
//*******************************************************************************************
// Configuration des ports série (celui du ST_Link et celui du module LoRa-E5)
// La biliothèque de Sylvain Montagny suppose :
// - Que le port série du ST-Link s'appelle "Debug_Serial" et qu'il a une vitesse de 115200 bauds
// - Que le port série du module LoRa-E5 s'appelle "LoRa_Serial" et qu'il a une vitesse de 9600 bauds
// Le fichier "config_board.h" précise les broches utilisées pour le module LoRa-E5.
#include "config_board.h"
// Bibliothèque pour la lecture du capteur BME280, choisie pour ses commandes permettant
// d'utiliser celui-ci en mode basse consommation.
#include <GyverBME280.h>
// Instance du capteur BME280
GyverBME280 bme;
// Variables globales pour les mesures
float temp; // Température (Celsius)
float pres; // Pression (hPa)
float humi; // Humidité relative (%)
// Offset de température du BME280
// (déterminé expérimentalement et différent pour chaque capteur)
#define TEMP_OFFSET (-2.1)
// Bibliothèque basse consommation pour le MCU STM32
#include "STM32LowPower.h"
// Configurations pour la communication LoRaWAN
// Bibliothèque pour l'utilisation du module LoRa-E5 (commandes AT)
#include "lorae5.h"
// Fichier pour renseigner les paramètres de la connexion LoRa
#include "config_application.h"
// Temps de sommeil du MCU STM32, en millisecondes, entre deux posts (10 minutes)
#define LOW_POWER_DURATION_MS 600000
#define PAYLOAD_SIZE 5 // Nombre d'octets dans les Payloads LoRaWAN
uint8_t payloadUp[PAYLOAD_SIZE]; // Réservation mémoire pour la payload "Uplink"
uint8_t payloadDown[PAYLOAD_SIZE]; // Réservation mémoire pour la payload "Downlink"
uint8_t sizePayloadUp = PAYLOAD_SIZE; // Taille de la payload "Uplink"
uint8_t sizePayloadDown = PAYLOAD_SIZE; // Taille de la payload "Downlink"
// Instanciation du module LoRa-E5, les paramètres sont dans le fichier config_application.h
LORAE5 lorae5(devEUI, appEUI, appKey, devAddr, nwkSKey, appSKey);
//*******************************************************************************************
// Initialisations
//*******************************************************************************************
void setup() {
// Initialisation des ports série du ST-Link et du module LoRa-E5
lorae5.setup_hardware(&Debug_Serial, &LoRa_Serial);
// Initialisation du BME280, pour utiliser le capteur en mode : "lis et rendors-toi !"
bme.setMode(FORCED_MODE);
bme.begin();
// Configuration du module LoRA-E5
lorae5.setup_lorawan(REGION, ACTIVATION_MODE, CLASS, SPREADING_FACTOR, ADAPTIVE_DR, CONFIRMED, PORT_UP, SEND_BY_PUSH_BUTTON, FRAME_DELAY);
// Affichage de la configuration
lorae5.printInfo();
// Réalisation du join "Over The Air Activation" (OTAA)
Debug_Serial.println("Procédure de join OTAA en cours ...");
while (!lorae5.join()) {};
delay(2000); // Temporisation de deux secondes
// Configure la LED utilisateur de la carte NUCLEO
pinMode(LED_BUILTIN, OUTPUT);
// Active le mode basse consommation du MCU STM32
LowPower.begin();
}
//*******************************************************************************************
// Boucle du programme principal
//*******************************************************************************************
void loop() {
Debug_Serial.println("\r\nMesure en cours ...");
// Allume la LED
digitalWrite(LED_BUILTIN, HIGH);
// Mesure de la température, de la pression et de l'humidité
measure();
// Construction de la payload LoRaWAN à partir des mesures
build_LoRaWAN_payload();
// Emission de la trame LoRaWAN
// Envoie "sizePayloadUp" octets depuis le tableau "payloadUp"
lorae5.sendData(payloadUp, sizePayloadUp);
// Vérifie si un Downlink est planifié sur RX1-RX2 (device de classe A)
// Appelle processDownlink() pour traiter les octets reçus le cas échéant.
if (lorae5.awaitForDownlinkClass_A(payloadDown, &sizePayloadDown) == RET_DOWNLINK){
processDownlink();
};
// Place le module LoRa-E5 en mode "basse consommation" jusqu'à la prochaine mesure
lorae5.sleep();
Debug_Serial.printf("Mise en veille pour %u secondes\r\n", LOW_POWER_DURATION_MS / 1000);
// Eteint la LED
digitalWrite(LED_BUILTIN, LOW);
Debug_Serial.flush(); // Vide le buffer du port série avant la mise en sommeil
delay(1000); // Temporisation blocante pendant 1 seconde
// Place le MCU STM32 en mode sommeil pendant LOW_POWER_DURATION_MS millisecondes
LowPower.shutdown(LOW_POWER_DURATION_MS);
}
//*******************************************************************************************
// Mesure de la température, de la pression et de l'humidité
//*******************************************************************************************
void measure(void) {
// Lance une lecture du capteur, il se remet en veille après
bme.oneMeasurement();
// Polling en attendant que la lecture soit terminée
while (bme.isMeasuring()) {};
// Réalisation des mesures avec le capteur
temp = bme.readTemperature() + TEMP_OFFSET;
pres = bme.readPressure() * 0.01;
humi = bme.readHumidity();
// Affichage des mesures
// Attention, pour que cela fonctionne correctement, activer
// "Newlib Nano + Float printf" dans le menu "Outils/C Runtime Library".
Debug_Serial.printf(" - Température : %.1f °C\r\n", temp);
Debug_Serial.printf(" - Pression : %1.f hPa\r\n", pres);
Debug_Serial.printf(" - Humidité relative : %.1f %%\r\n", humi);
}
//*******************************************************************************************
// Construction de la payload LoRaWAN
//*******************************************************************************************
void build_LoRaWAN_payload(void) {
// On convertit les mesures de température, pression et humidité en entiers pour décodage
// ultérieur avec TagoIO.
int16_t temp_ = round(10 * temp);
int16_t pres_ = round(10 * pres);
int16_t humi_ = round(2 * humi);
// Construction de la payload LoRaWAN, on agrège les données au format hexadécimal.
// Voir ce tutoriel :
// https://www.carnetdumaker.net/articles/quelques-fonctions-bien-pratiques-du-framework-arduino/
// pour quelques astuces sur les fonctions lowByte(x) et highByte(x) du framework Arduino qui
// permettent de simplifier le code ci-dessous.
// Température, donnée codée sur 16 bits
payloadUp[0] = (temp_ >> 8) & 0xFF; // Extraction de l'octet de poids faible
payloadUp[1] = temp_ & 0xFF; // Extraction de l'octet de poids fort
// Pression, donnée codée sur 16 bits
payloadUp[2] = (pres_ >> 8) & 0xFF; // Extraction de l'octet de poids faible
payloadUp[3] = pres_ & 0xFF; // Extraction de l'octet de poids fort
// Humidité, donnée codée sur un seul octet
payloadUp[4] = humi_;
}
//*******************************************************************************************
// Fonction de traitement d'un éventuel downlink
// Lorsque vous avez reçu "sizePayloadDown" octets dans le tableau "payloadDown" ...
//*******************************************************************************************
void processDownlink() {
Debug_Serial.println("Données reçues du serveur TTN :" );
for(uint8_t i = 0; i < sizePayloadDown; i++) {
Debug_Serial.print(payloadDown[i], HEX);
Debug_Serial.print("\r\n");
}
}
Mise en œuvre du sketch Arduino
Dans un premier temps, vous devez créer un fichier config_application.h
dans le même dossier que votre sketch LoRa_E5_Publish.ino
puis renseigner son contenu avec les informations nécessaires au join OTAA, comme ceci :
/***********************************************************************/
/* Please see README page on https://github.com/SylvainMontagny/LoRaE5 */
/***********************************************************************/
#define REGION EU868
#define ACTIVATION_MODE OTAA
#define CLASS CLASS_A
#define SPREADING_FACTOR 7
#define ADAPTIVE_DR false
#define CONFIRMED false
#define PORT_UP 15
#define SEND_BY_PUSH_BUTTON false
#define FRAME_DELAY 20000
String devEUI = "2C F7 F1 20 44 10 BA 4A";
// Configuration for ABP Activation Mode
String devAddr = "00000000";
String nwkSKey = "00000000000000000000000000000000";
String appSKey = "00000000000000000000000000000000";
// Configuration for OTAA Activation Mode
String appKey = "55 10 67 98 B2 15 EE 4E D0 33 19 DC 65 27 88 AB";
String appEUI = "00 00 00 00 00 00 00 00";
Nous rappelons que nous utilisons ici la “configuration OTAA” pour laquelle :
- La valeur de devEUI a été obtenue à l’aide de la commande AT+ID en première partie de ce tutoriel. Elle nous a ensuite servi pour obtenir appKey via TTN en deuxième partie de ce tutoriel.
- La valeur de appEui doit rester à “00 00 00 00 00 00 00 00”. En fait elle est arbitraire, mais elle doit être identique à celle renseignée dans la définition de l’objet, dans l’interface de TTN.
- La valeur de appKey a été obtenue au moment de la création d’une application via l’interface de TTN.
Dans un deuxième temps, vous devez créer un fichier config_board.h
dans le même dossier que votre sketch LoRa_E5_Publish.ino
puis renseigner son contenu avec les informations nécessaires pour la configuration des ports sérié utilisés, comme ceci :
// Alias pour l'UART du ST-Link (UART2)
#define Debug_Serial Serial
// Broches pour l'UART attribué au module LoRa-E5 (UART4)
#define RX_PIN_LORA PA1 // Broche A1 Arduino, brancher dessus la ligne TX du module LoRA-E5
#define TX_PIN_LORA PA0 // Broche A0 Arduino, brancher dessus la ligne RX du module LoRA-E5
// Initialisation de l'UART pour le module LoRa-E5
HardwareSerial LoRa_Serial(RX_PIN_LORA, TX_PIN_LORA);
Enfin, après avoir vérifié que l’IDE Arduino est correctement configurée, notamment qu’elle est connectée au port COM attribué au ST-LINK de votre carte (sous Windows), cliquez sur “Téléverser”.
Le baudrate du terminal série est imposé à 115200 bauds par la bibliothèque LoRaWAN-Seeed-Grove-Wio-E5, ne l’oubliez pas !
Vous devriez lire dans le terminal série de l’IDE Arduino la publication régulière, toutes les dix minutes, de trames LoRaWAN à l’attention des serveurs de TTN :
> LoRa-E5 board detected ...
# For more information visit : https://github.com/SylvainMontagny/LoRaE5
> OTAA
> CLASS_A
> SF 7
> ADR OFF
> Unconfirmed
> Port 15
* DevEUI 0x 2C F7 F1 20 44 10 BA 4A
* AppKey 0x 55 10 67 98 B2 15 EE 4E D0 33 19 DC 65 27 88 AB
* AppEUI-JoinEUI 0x 00 00 00 00 00 00 00 00
Procédure de join OTAA en cours ...
> SUCCESS JOINED OTAA !!!
> DevAddr = 44:10:BA:4A
Mesure en cours ...
- Température : 23.5 °C
- Pression : 952 hPa
- Humidité relative : 38.6 %
Sending Unconfirmed Data Up
- Payload UP 0x00 0xEB 0x25 0x2E 0x4D
- PortUp 15
- SF 7
Transmission Done
Waiting for Downlink...
MAC command received :
- Slot RX1
# Timeout reached.
Mise en veille pour 600 secondes
Complément : Downlink et receipt callback ?
Le sketch ci-avant contient aussi du code pour la réception de données descendantes ou downlink, depuis le serveur TTN sur le module LoRa-E5. Le protocole LoRaWAN permet en effet une communication bidirectionnelle objet <-> serveur. Nous n’utiliserons pas cette possibilité, mais nous pouvons néanmoins vérifier qu’elle fonctionne.
Pour envoyer un message depuis TTN au module LoRa-E5 …
- Rendez-vous sur la page de votre device ;
- Puis, dans le menu vertical à gauche, choisissez End devices ;
- Cliquez sur le device concerné ;
- Sélectionnez le sous menu Messaging ;
- Sélectionnez le sous-sous-menu Downlink;
- Finalement, entrez une valeur hexadécimale dans la boite Payload (deux caractères, simplement “0A” dans notre cas) et cliquez sur le bouton Schedule downlink en bas. Un message Downlink scheduled, en bas à droite, confirme que l’opération est planifiée. Pour notre device, voici l’aspect de la page de downlink sur le site de TTN à ce moment :
- Il vous faut attendre le prochain uplink du module LoRa-E5 vers le serveur TTN. Une fois celui-ci réalisé, le message du serveur est bien reçu par le module, comme le confirment les logs sur le terminal série :
> LoRa-E5 board detected ...
... (lignes supprimées par soucis de concision)
Transmission Done
Waiting for Downlink...
Receiving Data Down:
- Port 1
- Payload DOWN 0x0A 0x0B 0x0C 0x0D 0x0E
- Slot RX1
Données reçues du serveur TTN :
ABCDE
# Timeout reached.
Mise en veille pour 600 secondes
Visualisation des mesures sur TTN puis sur TagoIO
Cette dernière étape est identique à celle du tutoriel MicroPython disponible ici, que nous vous invitons à consulter. Le parser permettant de “décoder” la payload LoRaWAN est disponible dans l’archive ZIP téléchargeable. Vous le trouverez dans le fichier Parser_LoRaWAN.txt du dossier “\Publication LoRaWAN\LoRa_E5_Publish.
Liens et ressources
Sur LoRa et LoRaWAN en général :
L’installation d’une passerelle TTIG est abordée par notre tutoriel dédié, qui donne aussi d’autres références.
Bibliothèques Arduino pour piloter un module Grove LoRa-E5 avec des commandes AT :
Sur l’intégration TagoIO :
- Démarrer avec TagoIO
- Configurer TagoIO, tutoriel de TTN
- Intégration TagoIO avec TTN
- Configuration d’un Payload parser avec TagoIO
- Configuration d’un Payload parser LoRaWAN avec TagoIO
- Création d’un dashboard TagoIO
Pour une revue du module LoRa-E5 sur le blog disk91.co, c’est ici.
Concernant le module LoRa-E5, deux ressources qui expliquent aussi comment configurer un réseau LoRaWAN privé sur TTN :