Sending Sensor Data over LoRa

Pages
Contributors: Mariah
Favorited Favorite 5

Transmit/Receive Code

Once the libraries are installed, go ahead and open up two separate blank sketches in Arduino. One sketch will house the transmitter program, while the other will be for our receiver:

// Peer to Peer: Monitor Sensor Data using LoRa - Transmitter
// SparkFun Electronics, Mariah Kelly, November 2022
// Original transmit file can be found here: https://cdn.sparkfun.com/assets/learn_tutorials/1/4/9/4/Transmit-v3.ino

// Include necessary libraries
#include <RadioLib.h>         // Transmit & receive - https://github.com/jgromes/RadioLib/archive/refs/heads/master.zip
#include "SparkFunBME280.h"   // Qwiic Atmospheric Sensor library - https://github.com/sparkfun/SparkFun_BME280_Arduino_Library/archive/master.zip

// SX1262 has the following connections:
// NSS pin:   D36
// DIO1 pin:  D40
// NRST pin:  D44
// BUSY pin:  D39
SX1262 radio = new Module(D36, D40, D44, D39, SPI1);
BME280 mySensor;

void setup() {
  Serial.begin(115200);  // Remember to set this value in your serial monitor as well!
  Serial.println("Reading basic values from BME280");

  Wire.begin();   // Begin I2C communication

  if (mySensor.beginI2C() == false) {
    Serial.println("The sensor did not respond. Please check wiring.");
    while (1); //Freeze
  }

  // Initialize SX1262 with default settings
  Serial.print(F("[SX1262] Initializing ... "));

  int state = radio.begin(915.0, 250.0, 7, 5, 0x34, 20, 10, 0, false);;

  if (state == RADIOLIB_ERR_NONE) {
    Serial.println(F("success!"));
  } else {
    Serial.print(F("failed, code "));
    Serial.println(state);
    while (true);
  }
}

void loop() {

  Serial.println(F("[SX1262] Transmitting packet ... "));

  // Retrieve environmental data and declare as integers
  int temp = (int)mySensor.readTempF();
  int humidity = (int)mySensor.readFloatHumidity();
  int alt = (int)mySensor.readFloatAltitudeFeet();

  // Print to serial monitor (use this to double check that your sent data is correct and that your sensor is taking readings)
  Serial.print(temp);
  Serial.print(" Degrees ");
  Serial.print(humidity);
  Serial.print("% ");
  Serial.print(alt);
  Serial.println(" Feet");

  // Create a String to send (data must be sent as a string, so we'll tell our computer friend that we want our integers to be set as strings)
  String myData = String(temp) + " Degrees" + String(humidity) + "% Humid " +    String(alt) + " Feet";  // I added some units for our data here as well

  // Transmit data and units
  int state = radio.transmit(myData);

  if (state == RADIOLIB_ERR_NONE) {
    // The packet was successfully transmitted
    Serial.println(F("Success!"));

    // Print measured data rate
    Serial.print(F("[SX1262] Datarate:\t"));
    Serial.print(radio.getDataRate());
    Serial.println(F(" bps"));

  } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) {
    // The supplied packet was longer than 256 bytes
    Serial.println(F("Packet size too long!"));

  } else if (state == RADIOLIB_ERR_TX_TIMEOUT) {
    // Timeout occurred while transmitting packet
    Serial.println(F("Timeout!"));

  } else {
    // Some other error occurred
    Serial.print(F("Error"));
    Serial.println(state);
  }

  // Wait for a second before transmitting again
  delay(1000);
}

Once your transmitter is up and running, and you’re getting readings from your atmospheric sensor, we can move on to the receiver!

// Peer to Peer: Monitor Sensor Data using LoRa - Receiver
// SparkFun Electronics, Mariah Kelly, November 2022
// Original receive file can be found here: https://cdn.sparkfun.com/assets/learn_tutorials/1/4/9/4/Receive-v3.ino

// Include necessary libraries
#include <RadioLib.h>
#include <Wire.h>
#include <SFE_MicroOLED.h>  // Include the SFE_MicroOLED library

#define PIN_RESET 9
#define DC_JUMPER 1
MicroOLED oled(PIN_RESET, DC_JUMPER);    // I2C declaration

// SX1262 has the following connections:
// NSS pin:   10
// DIO1 pin:  2
// NRST pin:  3
// BUSY pin:  9
//SX1262 radio = new Module(10, 2, 3, 9);
SX1262 radio = new Module(D36, D40, D44, D39, SPI1);

void setup() {
  Serial.begin(9600);   // Remember to set this value in your serial monitor as well!

  Wire.begin();    // Begin I2C communication

  oled.begin();    // Initialize the OLED
  oled.clear(ALL); // Clear the display's internal memory
  oled.display();  // Display what's in the buffer (splashscreen)
  delay(1000);     // Delay 1000 ms
  oled.setFontType(0);
  oled.clear(PAGE); // Clear the buffer.

  randomSeed(analogRead(A0) + analogRead(A1));

  // initialize SX1262 with default settings
  Serial.print(F("[SX1262] Initializing ... "));

  int state = radio.begin(915.0, 250.0, 7, 5, 0x34, 20, 10, 0, false);

  if (state == RADIOLIB_ERR_NONE) {
    Serial.println(F("success!"));
  } else {
    Serial.print(F("failed, code "));
    Serial.println(state);
    while (true);
  }
}

void loop() {

  Serial.print(F("[SX1262] Waiting for incoming transmission ... "));

  String str;   // Declare a data type to receive (this must be a string)
  int state = radio.receive(str);   // Receive data from transmitter

  if (state == RADIOLIB_ERR_NONE) {
    // The packet was successfully received
    Serial.println(F("Success!"));

    // Print that the receiver was successful to the OLED screen (the back and forth of the "Success" text and data will act as a signifier that data is still being received!)
    oled.clear(PAGE);
    oled.setCursor(0, 0);
    oled.print("Success!");
    oled.display();
    delay(1000);

    // Print the data of the packet to the serial monitor
    Serial.print(F("[SX1262] Data:\t\t"));
    Serial.println(str);

    // Print the data of the packet to the OLED screen
    oled.clear(PAGE);
    oled.setCursor(0, 0);
    oled.print(str);
    oled.display();
    delay(2000);
    oled.clear(PAGE);

    // Print the RSSI (Received Signal Strength Indicator) of the last received packet
    Serial.print(F("[SX1262] RSSI:\t\t"));
    Serial.print(radio.getRSSI());
    Serial.println(F(" dBm"));

    // Print the SNR (Signal-to-Noise Ratio) of the last received packet
    Serial.print(F("[SX1262] SNR:\t\t"));
    Serial.print(radio.getSNR());
    Serial.println(F(" dB"));

  } else if (state == RADIOLIB_ERR_RX_TIMEOUT) {
    // Timeout occurred while waiting for a packet
    Serial.println(F("Timeout!"));    // We won't print this to the screen since the Success/data print will freeze on its own if a timeout occurs

  } else if (state == RADIOLIB_ERR_CRC_MISMATCH) {
    // The packet was received, but is malformed
    Serial.println(F("CRC error!"));

    // Print CRC Error message to OLED screen
    oled.clear(PAGE);
    oled.setCursor(0, 0);
    oled.print("CRC Error!");
    oled.display();
    delay(1000);
    oled.clear(PAGE);

  } else {
    // Some other error occurred
    Serial.print(F("Error"));
    Serial.println(state);

    // Print Error message to OLED screen
    oled.clear(PAGE);
    oled.setCursor(0, 0);
    oled.print("Error! ");
    oled.print(state);
    oled.display();
    delay(1000);
    oled.clear(PAGE);
  }
}

Now that our transmitter and receiver are chatting with each other, we can go out and test how far the signal will reach! Feel free to play around with your settings a bit, just remember to change them in both the transmitter and receiver settings AND to check your regional LoRa Frequency Band parameters (for the U.S. this range is 902 - 928MHz).

We managed to get 0.3 miles away before we had to turn around because of the highway, but were still getting a decent signal from there! Let us know how far you can go!

Exploring with LoRa