Communication directe entre modules LoRa-E5

Ce tutoriel explique comment mettre en œuvre une communication entre deux modules Grove LoRa-E5 en MicroPython. Il est constitué de trois parties :

  • Partie 1 : Piloter un module Grove LoRa-E5 avec des commandes AT
  • Partie 2 : Liaison entre deux modules avec des commandes AT
  • Partie 3 : Une station de mesure utilisant une connexion LoRa directe entre modules

Voici à quoi ressemble le module Grove LoRa-E5, “vedette” de ce tutoriel :

Module LoRa-E5


Crédit image : Seeed Studio

Le matériel radiofréquence LoRa est essentiellement destiné à la création de réseaux étendus et très basse consommation d’objets connectés (LoRaWAN, voir cette référence ou encore la page dédiée sur notre site).

Cependant, il est aussi possible de créer une liaison entre deux modules en utilisant un mode test prévu par la spécification LoRa. Nous faisons ici la démonstration de cette possibilité, intéressante dans le cas d’applications nécessitant de très faibles flux de données (quelques octets par seconde), comme par exemple en domotique. Et les performances des petits modules Grove LoRa-E5 sont étonnantes compte-tenu de leur antenne minimaliste : nous avons pu les faire communiquer approximativement à 190 mètres de distance, alors que deux murs occultaient le trajet de leur signal radio !

Partie 1 : Piloter un module Grove LoRa-E5 avec des commandes AT

Les modules Grove LoRa-E5 se connectent à un port série (UART) et sont pilotés à l’aide de “commandes AT”. Ceci signifie que Seeed Studio a programmé dans chaque module un firmware qui reçoit des commandes en mode texte et y répond, également par du texte, au moyen du protocole série UART. La même stratégie est souvent utilisée pour piloter des modules GPS, Wi-Fi ou Bluetooth. La documentation complète des commandes AT du module LoRa-E5 est disponible ici.

Matériel requis et montage

Pour cette partie nous utiliserons le matériel suivant :

  1. Deux modules Grove LoRa-E5, basé sur un système sur puce (SoC) STM32WLE5JC de STMicroelectronics.
  2. Deux cartes d’extension de base Grove avec leurs commutateurs d’alimentation en position 3.3V.
  3. Deux cartes NUCLEO-WB55.

Assemblez deux systèmes identiques, pour chacun d’eux placez la carte d’extension Grove sur la carte NUCLEO et connectez le module LoRa-E5 sur le connecteur UART. NB : Pour économiser quelques euros, les cartes d’extension de base Grove peuvent être remplacées par des câbles Grove - Dupont femelle.

Le script MicroPython

Le script présenté ci-après est disponible dans cette archive ZIP à l’intérieur du dossier Communication P2P modules LoRa-E\Commandes AT\.

Dans ce tutoriel, nous allons utiliser des commandes AT pour réaliser la connexion. Nous avons donc besoin d’un script MicroPython capable de recueillir les commandes AT que nous taperons dans le terminal PuTTY (connecté à l’interpréteur MicroPython installé sur la NUCLEO-WB55) et de les envoyer au module Grove LoRa-E5. C’est précisément la fonction du script qui suit, inspiré des exemples donnés sur cette page.
Créez un script main.py sur votre ordinateur et copiez-y le code suivant, puis glissez-déplacez le dans PYBFLASH :

# Objet du script : Emission / Réception de messages via UART en mode ligne de commande
# Ce script est utile pour dialoguer avec des modules dotés de firmwares AT.
# Il est paramétré ici (UART_NUMBER, BAUDRATE, EOL) pour la communication avec un module
# Grove LoRa-E5 conneté à une carte NUCLEO-WB55.

from machine import UART # Pour piloter l'UART

# Constantes relatives au paramétrage de l'UART
DELAY_TIMEOUT = const(1000) # Durée (en millisecondes) pendant laquelle l'UART attend de reçevoir un message
BAUDRATE = const(9600)	# Débit, en bauds, de la communication série
UART_NUMBER = const(2)	# Identifiant de l'UART de la carte NUCLEO-WB55 qui sera utilisé
RX_BUFF = const(512)	# Taille du buffer de réception (les messages reçus seront tronqués 
						# à ce nombre de caractères)

EOL = "\r\n" # Terminaison de commande pour valider l'envoi

# Initialisation de l'UART
uart = UART(UART_NUMBER, BAUDRATE, timeout = DELAY_TIMEOUT, rxbuf = RX_BUFF)

# Fonction de service de l'interruption de réception de l'UART
@micropython.native # Optimise le bytecode pour STM32
def Reception(uart_object):

	# Lecture des caractères reçus
	message_received = uart_object.read()

	# Si réception d'un message
	if not (message_received is None):
		# Affiche le message reçu
		print("Message reçu : " + message_received.decode("utf-8"))
	
	print("Entrez votre commande : ", end='')
		
# On active l'interruption de l'UART (vecteur d'interruption) pour la réception
irq_uart = uart.irq(Reception, UART.IRQ_RXIDLE, False)

# Pour gérer l'envoi de messages
@micropython.native # Optimise le bytecode pour STM32
def Emission():
	
	while True:
	
		# Prompt de saisie d'un message (au clavier)
		message_sent = input()
		
		# Envoi du message saisi
		uart.write(message_sent + EOL)
		print("Envoyé : " + str(message_sent))

# Appel de la fonction principale
Emission()

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.

Test de la commande “AT”

Connectez un terminal PuTTY au firmware MicroPython de chacune des deux cartes NUCLEO-WB55, comme indiqué ici (systèmes Windows), et lancez le script avec [CTRL]-[D]. Pour vous assurer que tout fonctionne bien tapez simplement AT dans le terminal, puis ENTER. La console PuTTY devrait ressembler à ceci dans les deux cas :

MicroPython v1.20.0 on 2023-04-26; NUCLEO-WB55 with STM32WB55RGV6
Type "help()" for more information.
>>>
MPY: sync filesystems
MPY: soft reboot
Entrez votre commande
AT
Envoyé : AT
Message reçu : +AT: OK

Tout va bien, les modules Grove LoRa-E5 vous ont répondu +AT: OK comme prévu. Nous pouvons donc poursuivre notre tutoriel !

Partie 2 : Communication directe entre modules avec des commandes AT

A présent, nous pouvons configurer les deux systèmes (chacun constitué d’une NUCLEO-WB55 et d’un module Grove LoRa-E5) pour les faire communiquer. Un sera paramétré comme émetteur, et l’autre comme récepteur.

Matériel requis et montage

Pour cette partie nous utiliserons le matériel suivant :

  1. Deux modules Grove LoRa-E5, basé sur un système sur puce (SoC) STM32WLE5JC de STMicroelectronics.
  2. Deux cartes d’extension de base Grove avec leurs commutateurs d’alimentation en position 3.3V.
  3. Deux cartes NUCLEO-WB55.

Assemblez deux systèmes identiques, pour chacun d’eux placez la carte d’extension Grove sur la carte NUCLEO et connectez le module LoRa-E5 sur le connecteur UART. NB : Pour économiser quelques euros, les cartes d’extension de base Grove peuvent être remplacées par des câbles Grove - Dupont femelle.

Configuration de l’émetteur

Choisissez une NUCLEO-WB55 + LoRa-E5 et adressez lui la séquence de commande AT qui suit, via PuTTY :

Pour passer en mode test : AT+MODE=TEST

Ce qui donne, sur la console PuTTY de l’émetteur :

MicroPython v1.20.0 on 2023-04-26; NUCLEO-WB55 with STM32WB55RGV6
Type "help()" for more information.
>>>
MPY: sync filesystems
MPY: soft reboot
Entrez votre commande
AT+MODE=TEST
Envoyé : AT+MODE=TEST
Message reçu : +MODE: TEST

Par défaut, le mode test suppose un comportement émetteur, nous n’avons donc aucune autre commande AT à communiquer au module.

Configuration du récepteur

Prenez l’autre NUCLEO-WB55 + LoRa-E5 et adressez lui la séquence de commandes AT qui suit, via PuTTY :

Pour passer en mode test : AT+MODE=TEST
Pour passer en mode réception : AT+TEST=RXLRPKT

Ce qui donne, sur la console PuTTY du récepteur :

MicroPython v1.20.0 on 2023-04-26; NUCLEO-WB55 with STM32WB55RGV6
Type "help()" for more information.
>>>
MPY: sync filesystems
MPY: soft reboot
Entrez votre commande
AT+MODE=TEST
Envoyé : AT+MODE=TEST
Message reçu : +MODE: TEST

Entrez votre commande
AT+TEST=RXLRPKT
Envoyé : AT+TEST=RXLRPKT
Message reçu : +TEST: RXLRPKT

Envoi d’un message

Rendez-vous sur la console de l’émetteur et validez :

  • Ceci pour envoyer un message en mode “chaîne de caractères hexadécimaux” :
    AT+TEST=TXLRPKT, "0123456789ABCDEF0123456789ABCDEF"
    Cette commande ne peut envoyer que des messages constitués des 16 caractères de la base hexadécimale.

  • Ceci pour envoyer un message en mode “chaîne de caractères ASCII” :
    AT+TEST=TXLRSTR, "Je suis un novice pardi !"
    Cette commande peut envoyer n’importe quelle chaîne de caractère ASCII.

Ce qui donne, sur la console PuTTY de l’émetteur :

>>>
MPY: sync filesystems
MPY: soft reboot
Entrez votre commande
AT+MODE=TEST
Envoyé : AT+MODE=TEST
Message reçu : +MODE: TEST

Entrez votre commande
AT+TEST=TXLRPKT, "0123456789ABCDEF0123456789ABCDEF"
Envoyé : AT+TEST=TXLRPKT, "0123456789ABCDEF0123456789ABCDEF"
Message reçu : +TEST: TXLRPKT "0123456789ABCDEF0123456789ABCDEF"
+TEST: TX DONE

AT+TEST=TXLRSTR, "Je suis un novice pardi !"
Envoyé : AT+TEST=TXLRSTR, "Je suis un novice pardi !"
Message reçu : +TEST: TXLRSTR "Je suis un novice pardi !"
+TEST: TX DONE

Et les messages sont bien transmis, on le vérifie avec la console PuTTY du récepteur :

>>>
MPY: sync filesystems
MPY: soft reboot
Entrez votre commande
Message reçu : +TEST: LEN:1, RSSI:-43, SNR:13
+TEST: RX "0123456789ABCDEF0123456789ABCDEF"

Message reçu : +TEST: LEN:2, RSSI:-39, SNR:13
+TEST: RX  "4A65207375697320756E206E6F766963652070617264692021"

On remarque que, du côté récepteur, les messages sont toujours décodés avec les symboles de la base hexadécimale. Donc, pour le deuxième message envoyé en mode texte, un peu de codage sera nécessaire afin de transformer “4A65207375697320756E206E6F766963652070617264692021” en “Je suis un novice pardi !” dans une éventuelle application.
La solution en Python est étonnamment compacte :

# Chaîne de caractères hexadécimaux reçue en P2P par le module LoRa-E5 :
string_of_bytes = "4A65207375697320756E206E6F766963652070617264692021"

# Conversion de cette chaîne en sa représentation ASCII (lisible) ;
# string_of_chars contiendra : "Je suis un novice pardi !"
string_of_chars = bytearray.fromhex(string_of_bytes).decode()


Nous disposons à présent de tous les éléments pour programmer un système communiquant en LoRa, ce sera l’objet de la troisième partie de notre tutoriel !

Partie 3 : Une station de mesure utilisant LoRa

Les modules LoRa-E5 ne permettent pas de réaliser une connexion full duplex ; à un moment donné un module doit être récepteur et l’autre émetteur, mais les deux ne peuvent pas être simultanément émetteur et récepteur. Cependant en s’inspirant des sessions REPL déjà présentées il est possible de créer des scripts permettant d’alterner les rôles et de réaliser une communication half duplex, façon “talkie-walkie”. C’est ce que nous allons faire à présent en réalisant une station de mesure de la température constituée d’une base (station de commande) et d’un (ou plusieurs) satellite(s) (stations de mesure) connecté(s) en LoRa.

Le système que nous allons construire est résumé par le schéma suivant :

Station de mesure de température base-satellites


Le système est constitué d’une base (COMMAND_01) , un hub qui fera office de station de commande des mesures et de satellites (un seul ici, MEASURE_01) qui seront autant de stations de mesures connectées à la base par une liaison LoRa. En pratique, nous ne réaliserons qu’un seul exemplaire de la base et un seul satellite, mais la création d’un réseau en étoile est quasiment immédiate en multipliant les satellites, à un bémol près : il faudrait gérer des problématique d’appairage et de chiffrement (voir “Pour aller plus loin” ci-après) car tous les messages LoRa échangés le seront en broadcast, directement accessibles à qui voudra les écouter.

La base COMMAND_01, station de commande

Chaque base est chargée de capter les mesures de température contenues dans les messages LoRa de tous les satellites à sa portée. Elle publie également des messages LoRa toutes les cinq minutes à l’attention de ces satellites. Ces messages indiquent aux satellites qu’ils doivent effectuer une nouvelle mesure de température et la publier.

Une base est constituée du matériel suivant :

  1. Un module Grove UART LoRa-E5.
  2. Une carte d’extension de base Grove avec son commutateur d’alimentation en position 3.3V.
  3. Une carte NUCLEO-WB55.
  4. Un module Grove I2C - OLED Display 0.96” (SSD1308Z).

Branchez les différents modules sur les prises correspondantes de la carte d’extension de base Grove.

Le script pour la base est disponible dans cette archive ZIP à l’intérieur du dossier \Communication modules LoRa-E\Base-Satellite\Base\.
Nous ne le reproduisons pas ici afin de ne pas surcharger le tutoriel.

Copier les fichiers main.py et ssd1308.py dans le périphérique PYBFLASH.

Le satellite MEASURE_01, station de mesure

Chaque satellite est chargé de prendre les mesures de température à l’aide de son module BME280. Ensuite, il les publie en LoRa, afin qu’ils soient interceptés et affichés par d’éventuelles bases à portée de réception. Enfin, il attend un message LoRa en retour de ces bases qui lui demandera d’effectuer et publier une nouvelle mesure.

Un satellite est constitué du matériel suivant :

  1. Un module Grove UART LoRa-E5.
  2. Une carte d’extension de base Grove avec son commutateur d’alimentation en position 3.3V.
  3. Une carte NUCLEO-WB55.
  4. Un module Grove I2C - OLED Display 1.12” (SSD1327).
  5. Un module Grove I2C - BME280.

Branchez les différents modules sur les prises correspondantes de la carte d’extension de base Grove.

Le script pour les satellites est disponible dans cette archive ZIP à l’intérieur du dossier \Communication modules LoRa-E\Base-Satellite\Satellite\.
Nous ne le reproduisons pas ici afin de ne pas surcharger le tutoriel.

Copier les fichiers main.py, bme280.py et ssd1327.py dans le périphérique PYBFLASH.

Mise en œuvre et performances de la liaison LoRa base - satellites

Dans cet ordre :

  • Commencez par vous connecter au terminal REPL de la station de commande avec PuTTY puis lancez le script main.py avec avec [CTRL]-[D].
  • Ensuite, connectez vous au terminal REPL de la station de mesure avec PuTTY puis lancez le script main.py avec avec [CTRL]-[D].

Après quelques instants, la connexion entre les deux stations devrait être confirmée. Après dix minutes, les logs (et les écrans OLED) devraient confirmer l’échange régulier de données entre elles :

  • Les logs PuTTY / REPL de la station de base :
MicroPython v1.20.0 on 2023-04-26; NUCLEO-WB55 with STM32WB55RGV6
Type "help()" for more information.
>>>
MPY: sync filesystems
MPY: soft reboot
Je suis COMMAND_01
-------------------------------------------------------
Initialisation du mode récepteur
L'objet est en mode récepteur !
-------------------------------------------------------
Payload reçue de MEASURE_01 : 26.3C, RSSI:-20 dBm
-------------------------------------------------------
Initialisation du mode émetteur
L'objet est en mode émetteur !
-------------------------------------------------------
Message envoyé : AT+TEST=TXLRSTR,"GO"
-------------------------------------------------------
Initialisation du mode récepteur
L'objet est en mode récepteur !
-------------------------------------------------------
Payload reçue de MEASURE_01 : 26.5C, RSSI:-20 dBm
-------------------------------------------------------
  • Les logs PuTTY / REPL de la station de mesure :
MicroPython v1.20.0 on 2023-04-26; NUCLEO-WB55 with STM32WB55RGV6
Type "help()" for more information.
>>>
MPY: sync filesystems
MPY: soft reboot
Je suis MEASURE_01
-------------------------------------------------------
Initialisation du mode émetteur
L'objet est en mode émetteur !
-------------------------------------------------------
Message envoyé : AT+TEST=TXLRSTR,"MEASURE_01|26.3"
-------------------------------------------------------
Initialisation du mode récepteur
L'objet est en mode récepteur !
-------------------------------------------------------
MicroPython v1.20.0 on 2023-04-26; NUCLEO-WB55 with STM32WB55RGV6
Type "help()" for more information.
>>> Message reçu : GO
-------------------------------------------------------
Initialisation du mode émetteur
L'objet est en mode émetteur !
-------------------------------------------------------
Message envoyé : AT+TEST=TXLRSTR,"MEASURE_01|26.5"
-------------------------------------------------------
Initialisation du mode récepteur
L'objet est en mode récepteur !
-------------------------------------------------------

Performances de la connexion radio : le RSSI

Les RSSI de nos exemples sont ici très faibles car les deux stations sont connectées sur le même ordinateur et à quelques centimètres de distance. L’expérience sera bien sûr plus ludique si vous connectez les deux stations sur des ordinateurs distants.

En fait, il suffit de les alimenter pour que les scripts main.py démarrent, un ordinateur et sa console REPL ne sont donc pas nécessaires (les écrans OLED permettent de lire l’activité des stations sans avoir recours à des ordinateurs).

Nous avons pu vérifier que la connexion radio entre la base et son satellite restait stable après les avoir séparés de 190 mètres, et placés chacun dans un bâtiment différent, tout ceci pour un RSSI fluctuant entre -115 dBm et -104 dBm. La sensibilité maximale théorique de la technologie LoRa étant de -149 dBm, il nous reste encore de la marge.

Et la communication est aussi très bonne dans un même bâtiment. Entre la cave et le premier étage le RSSI mesuré est de -85 dBm, de quoi répondre aux besoins d’une application domotique lorsque le Wi-Fi est inopérant !

Ce n’est pas mal du tout pour nos petits modules avec une antenne minimaliste qui se résume à un fil de fer “roulé en ressort” !

Pour aller plus loin

Voici trois pistes d’améliorations pour notre système :

  • Associer les satellites à une base identifiée
    Notre système présente un défaut (lié à la problématique de cybersécurité évoquée ci-après) : toutes les bases/stations de commande sont capables de capter tous les messages de tous les satellites/stations de mesures. Il manque donc dans nos scripts des tests supplémentaires et une procédure d’appairage avec authentification pour qu’une base donnée ne soit à l’écoute que des satellites que vous désirez lui associer.

  • Sécuriser les communications base-satellites
    Nous vous proposons d’améliorer l’application en y ajoutant un peu de cryptographie. La communication que nous avons démontrée n’est absolument pas sécurisée. En effet, tous les modules LoRa configurés en récepteurs et assez proches de l’émetteur vont capter ses messages et pourront les lire “en clair”. Pour toute application digne de ce nom, il conviendrait de crypter les messages avant leur émission et de les décrypter à leur réception, en utilisant une méthode de cryptographie symétrique à clef privée par exemple, basée sur une fonction XOR appliquée aux octets transmis de sorte qu’un couple émetteur-récepteur donné puisse échanger sans risque d’être espionné.
    Et si le sujet de la cybersécurité vous intéresse tout particulièrement, vous pouvez aussi explorer les possibilités offertes par les bibliothèques présentées à cette adresse..

  • Horodater les mesures des satellites
    Il manque une fonction essentielle à notre système : l’horodatage des mesures. Ceci est d’autant plus problématique que notre station n’est pas connectée à l’Internet. Nous vous invitons à rechercher une solution à cette lacune !

Liens et ressources

Sur LoRa (et LoRaWAN) en général :

Une revue du module LoRa-E5 sur le blog disk91.com : c’est ici.

Pour de la communication directe entre des module(s) LoRa-E5 :