Exercice avec la carte de communication LoRa/LoRaWAN I-NUCLEO-LRWAN1 en C/C++ pour Stm32duino

Vous devez disposez de la carte de communication LoRa/LoRaWAN I-NUCLEO-LRWAN1 pour continuer ces exercices.

Vous devez également disposez du compte sur un réseau LoRaWAN (TTN, CampusIoT, Orange, Objetnious) pour enregistrer votre carte LoRaWAN.

Démarrage

La carte I-NUCLEO-LRWAN1 est une carte de communication LoRa/LoRaWAN muni d’un modem AT USI. Elle est munie d’un connecteur Grove I2C et les capteurs MEMS de ST Microelectronics suivants :

  • LSM303AGR: acceleromètre et magnetomètre
  • LPS22HB: baromètre
  • HTS221: humidité et température

Le connecteur Grove et ces capteurs sont raccordés au bus I2C de la carte P-NUCLEO-WB55.

image

La schématique de la carte est disponible ici.

Branchement

La carte I-NUCLEO-LRWAN1 ne peut pas être directement sur plusieurs des NUCLEO 64 (F411RE par exemple): les 6 broches de carte I-NUCLEO-LRWAN1 doivent être raccordées aux broches des connecteurs Morpho des NUCLEO de la manière suivante:

I-NUCLEO-LRWAN1  --> NUCLEO-64
GND              --> GND   (CN7 Broche 16)
3.3V             --> 3.3V  (CN7 Broche 20)
RX/D0            --> PA_12 (CN10 Broche 12)
TX/D1            --> PA_11 (CN10 Broche 14)
SCL/D15          --> SCL (CN10 Broche 1)
SDA/D14          --> SDA (CN10 Broche 3)

Installation des bibliothèques pour la carte d’extension IKS01A3

Sur Windows

A faire

Sur Linux

A faire

Sur MacOS

Entrez les commandes suivantes :

cd ~/Documents/Arduino/libraries/
for lib in I-NUCLEO-LRWAN1 LSM303AGR LPS22HB HTS221
do
wget https://codeload.GitHub.com/stm32duino/${lib}/zip/master -O ${lib}-master.zip
unzip ${lib}-master.zip
done 

Utilisation

Lancez l’IDE Arduino (préalablement configuré pour Stm32duino).

Relancer l’IDE Arduino si les exemples de la bibliothèque n’apparait pas dans le menu Fichier > Exemples.

Ouvrez le croquis d’exemple Fichier > Exemples > STM32Duino I-NUCLEO-LRWAN1 > getInfo.

Changez les lignes suivantes.

//HardwareSerial SerialLora(D0, D1);
HardwareSerial SerialLora(PA_12, PA_11);

Ouvrez la console série qui affiche les traces suivantes:

-- Get Info sketch --
Firmware version: 1.1

LoRa stack version: 1.0.1
Unique DevEUI: 0xe24f43fffe441234
Application EUI: 0x2fa6ef9aa9df9ed8
Application key: 0x12345678123456781234567812345678
Network session Key: 0x75680f808410150f9c1fe349df6cc20d
Application session key: 0x11798c97be2ecbc596fd99a6e4d4a1d8
Device address: 0x12345678

Notez le DevEUI du modem.

Enregistrez un nouveau équipement sur le Network Server au moyen de votre compte avec le DevEUI, l’AppEUI de l’application et un AppKey que vous aurez choisi au hasard.

Editez un nouveau croquis inspiré de l’exemple Fichier > Exemples > STM32Duino I-NUCLEO-LRWAN1 > LoRaWANOTAA.

#include "LoRaWANNode.h"

#define FRAME_DELAY 300000  // in ms. Every 5 minutes by default.

// Serial port use to communicate with the USI shield.
// By default, use D0 (Rx) and D1(Tx).
// For NUCLEO64, see "Known limitations" chapter in the README.md

//HardwareSerial SerialLora(D0, D1);
HardwareSerial SerialLora(PA_12, PA_11);

// AppKey and AppEUI.
const char appKey[] = "12345678123456781234567812345678";
const char appEUI[] = "2fa6ef9aa9df9ed8";

// Data send
char frameTx[] = "Hello world!";

void setup()
{
  Serial.begin(115200);
  Serial.println("\n-- LoRaWAN OTAA sketch --");

  // Enable the USI module and set the radio band.
  while(!loraNode.begin(&SerialLora, LORA_BAND_EU_868)) {
    Serial.println("Lora module not ready");
    delay(1000);
  }

  String str = "DevEUI:  0x";
  loraNode.getDevEUI(&str);
  Serial.println(str);

  Serial.println("Joining ...");
  // Send a join request and wait the join accept
  while(!loraNode.joinOTAA(appKey, appEUI)) {
    Serial.println("joinOTAA failed!!");
    delay(1000);
  }

  Serial.println("Lora module ready, OTAA join accepted.\n");

  str = "AppEUI:  0x";
  loraNode.getAppEUI(&str);
  Serial.println(str);
  
  str = "AppKey:  0x";
  loraNode.getAppKey(&str);
  Serial.println(str);

  str = "DevAddr: 0x";
  loraNode.getDevAddr(&str);
  Serial.println(str);
}

void loop()
{
  receive();
  transmit();
  delay(FRAME_DELAY);
}

void receive(void) {
  uint8_t frameRx[64];
  uint8_t len;
  uint8_t port;

  // Check if data received from a gateway
  if(loraNode.receiveFrame(frameRx, &len, &port)) {
    uint8_t n = 0;
    Serial.print("frame received: 0x");
    while(len > 0) {
      Serial.print(frameRx[n], HEX);
      Serial.print(',');
      len--;
      n++;
    }
    Serial.print(" on port "); Serial.println(port);
  } else {
    Serial.println("No downlink data");
  }
}

void transmit(void) {
  // Send unconfirmed data to a gateway (port 1 by default)
  int status = loraNode.sendFrame(frameTx, sizeof(frameTx), UNCONFIRMED);
  if(status == LORA_SEND_ERROR) {
    Serial.println("Send frame failed!!!");
  } else if(status == LORA_SEND_DELAYED) {
    Serial.println("Module busy or duty cycle");
  } else {
    Serial.println("Uplink frame sent");
  }
}

Changez la valeur de la clé AppKey et de l’identifiant d’application AppEUI dans le croquis.

Compilez et chargez le binaire produit.

Ouvrez la console série qui affiche les traces suivantes:

DevEUI:  0xe24f43fffe441234
Joining ...
joinOTAA failed!!
joinOTAA failed!!
Lora module ready, OTAA join accepted.

AppEUI:  0x2fa6ef9aa9df9ed8
AppKey:  0x12345678123456781234567812345678
DevAddr: 0x12345678
No downlink data
Uplink frame sent

Envoi des mesures des capteurs via LoRaWAN

Créez un nouveau croquis avec le code ci-dessous en modifiant les valeurs de l’AppKey et l’AppEUI.

#include "LoRaWANNode.h"

#include <HTS221Sensor.h>
#include <LPS22HBSensor.h>
#include <LSM303AGR_ACC_Sensor.h>
#include <LSM303AGR_MAG_Sensor.h>

#define FRAME_DELAY 300000  // in ms. Every 5 minutes by default.

// Serial port use to communicate with the USI shield.
// By default, use D0 (Rx) and D1(Tx).
// For NUCLEO64, see "Known limitations" chapter in the README.md

//HardwareSerial SerialLora(D0, D1);
HardwareSerial SerialLora(PA_12, PA_11);

#define DEV_I2C Wire

// Components.
HTS221Sensor  *HumTemp;
LSM303AGR_ACC_Sensor *Acc;
LSM303AGR_MAG_Sensor *Mag;
LPS22HBSensor *PressTemp;


// AppKey and AppEUI.
const char appKey[] = "e24f43fffe44cf482fa6ef9aa9df9ed8";
const char appEUI[] = "2fa6ef9aa9df9ed8";

// Data send
struct __attribute__((packed)) frameTx_t {
  int16_t temperature;
  uint8_t humidity;
};
struct frameTx_t frameTx;

// Data send
//char frameTx[] = "Hello world!";

void setupSensors() {
  // Initialize I2C bus.
  DEV_I2C.begin();

  // Initlialize components.
  HumTemp = new HTS221Sensor (&DEV_I2C);
  HumTemp->Enable();

  PressTemp = new LPS22HBSensor(&DEV_I2C);
  PressTemp->Enable();

  Acc = new LSM303AGR_ACC_Sensor(&DEV_I2C);
  Acc->Enable();
  Acc->EnableTemperatureSensor();
  Mag = new LSM303AGR_MAG_Sensor(&DEV_I2C);
  Mag->Enable();

}

void readSensors() {
  
  // Read humidity and temperature.
  float temp1, hum;
  HumTemp->GetTemperature(&temp1);
  HumTemp->GetHumidity(&hum);

  Serial.print("HTS221   : ");
  Serial.print("Hum[%]: ");
  Serial.print(hum, 0);
  Serial.print(" | Temp[C]: ");
  Serial.print(temp1, 2);
  Serial.println(" |");

  frameTx.humidity = hum;
  frameTx.temperature = temp1 * 100;

  float pressure, temp2;
  PressTemp->GetPressure(&pressure);
  PressTemp->GetTemperature(&temp2);

  Serial.print("LPS22HB  : ");
  Serial.print("Pres[hPa]: ");
  Serial.print(pressure, 2);
  Serial.print(" | Temp[C]: ");
  Serial.print(temp2, 2);
  Serial.println(" |");

  // TODO add the frameTx

  // Read accelerometer LSM303AGR.
  int32_t accelerometer[3];
  Acc->GetAxes(accelerometer);

  // Read temperature LSM303AGR.
  float temp3;
  Acc->GetTemperature(&temp3);
  
  // Read magnetometer LSM303AGR.
  int32_t magnetometer[3];
  Mag->GetAxes(magnetometer);

  // Output data.
  Serial.print("LSM303AGR: ");
  Serial.print("Acc[mg]: ");
  Serial.print(accelerometer[0]);
  Serial.print(" ");
  Serial.print(accelerometer[1]);
  Serial.print(" ");
  Serial.print(accelerometer[2]);
  Serial.print(" | Mag[mGauss]: ");
  Serial.print(magnetometer[0]);
  Serial.print(" ");
  Serial.print(magnetometer[1]);
  Serial.print(" ");
  Serial.print(magnetometer[2]);
  Serial.print(" | Temp[C]: ");
  Serial.print(temp3, 2);
  Serial.println(" |");

  // TODO add the frameTx
}
void setup()
{
  Serial.begin(115200);
  Serial.println("\n-- LoRaWAN OTAA sketch --");

  setupSensors();

  // Enable the USI module and set the radio band.
  while(!loraNode.begin(&SerialLora, LORA_BAND_EU_868)) {
    Serial.println("Lora module not ready");
    delay(1000);
  }

  String str = "DevEUI:  0x";
  loraNode.getDevEUI(&str);
  Serial.println(str);

  Serial.println("Joining ...");
  // Send a join request and wait the join accept
  while(!loraNode.joinOTAA(appKey, appEUI)) {
    Serial.println("joinOTAA failed!!");
    delay(1000);
  }

  Serial.println("Lora module ready, OTAA join accepted.\n");

  str = "AppEUI:  0x";
  loraNode.getAppEUI(&str);
  Serial.println(str);
  
  str = "AppKey:  0x";
  loraNode.getAppKey(&str);
  Serial.println(str);

  str = "DevAddr: 0x";
  loraNode.getDevAddr(&str);
  Serial.println(str);
}

void loop()
{
  receive();
  transmit();
  delay(FRAME_DELAY);
}

void receive(void) {
  uint8_t frameRx[64];
  uint8_t len;
  uint8_t port;

  // Check if data received from a gateway
  if(loraNode.receiveFrame(frameRx, &len, &port)) {
    uint8_t n = 0;
    Serial.print("frame received: 0x");
    while(len > 0) {
      Serial.print(frameRx[n], HEX);
      Serial.print(',');
      len--;
      n++;
    }
    Serial.print(" on port "); Serial.println(port);
  } else {
    Serial.println("No downlink data");
  }
}

void transmit(void) {
  readSensors();
  
  // Send unconfirmed data to a gateway (port 1 by default)
  int status = loraNode.sendFrame((char*)&frameTx, sizeof(frameTx), UNCONFIRMED);
  //int status = loraNode.sendFrame(frameTx, sizeof(frameTx), UNCONFIRMED);
  if(status == LORA_SEND_ERROR) {
    Serial.println("Send frame failed!!!");
  } else if(status == LORA_SEND_DELAYED) {
    Serial.println("Module busy or duty cycle");
  } else {
    Serial.println("Uplink frame sent");
  }
}

Ouvrez la console série qui affiche les traces suivantes :

-- LoRaWAN OTAA sketch --
DevEUI:  0xe24f43fffe441234
Joining ...
joinOTAA failed!!
joinOTAA failed!!
Lora module ready, OTAA join accepted.

AppEUI:  0x2fa6ef9aa9df9ed8
AppKey:  0x12345678123456781234567812345678
DevAddr: 0x12345678
No downlink data
HTS221   : Hum[%]: 0 | Temp[C]: 17.00 |
LPS22HB  : Pres[hPa]: 31.96 | Temp[C]: -1.30 |
LSM303AGR: Acc[mg]: 0 0 0 | Mag[mGauss]: 0 0 0 | Temp[C]: 26.67 |
Uplink frame sent

Documentation

Les sources de la bibliothèque sont dans https://GitHub.com/stm32duino/I-NUCLEO-LRWAN1

La datasheet du module I-NUCLEO-LRWAN1 est disponible ici

Le site officiel de la LoRa Alliance est ici