The best tools to make your project dreams come true

Login or Signup
USD


By ShawnHymel

Arduino LoRa Weather Sensor

As part of my upcoming "Arduino Project to Product" series, I created a simple (but somewhat realistic) Internet of Things (IoT) project to showcase how a microcontroller might be used to send sensor data from a remote location. The series will dive into tricks to lower power consumption and prepare the widget for manufacturing.

The series does not delve into the LoRa project itself, as it is only used for demonstration purposes. If you'd like to recreate the project or use it as a starting point for your own LoRa project, you are welcome to use the code and directions found here.

Required Parts

Hardware Setup

Connect the Arduino as shown:

arduino-client

Connect the Raspberry Pi as shown:

rpi-server

Arduino Software

Install the following libraries for Arduino:

Copy Code
/**

* LoRa Weather Client

*

* Author: Shawn Hymel

* Date: March 23, 2019

*

* Transmits temperature, humidity, and pressure data over raw

* LoRa radio. Reads data from BME280 sensor and transmits with

* following packet:

*

* | 1B From Addr | 1B To Addr | 2B Temp | 2B Humd | 2B Pres |

*

* Note that temperature, humidity, and pressure values are

* scaled up by 10 and rounded to nearest integer before being

* sent. The server will need to scale received values by 1/10.

* This is to avoid sending full floating point values.

*

* Required libraries:

* - http://www.airspayce.com/mikem/arduino/RadioHead/ (v1.59)

* - https://github.com/adafruit/Adafruit_Sensor

* - https://github.com/adafruit/Adafruit_BME280_Library

*

* License: Beerware

*/


#include <Wire.h>

#include <SPI.h>


#include <Adafruit_Sensor.h>

#include <Adafruit_BME280.h>

#include <RH_RF95.h>


#define DEBUG 0


// Parameters

const uint8_t LORA_NODE_ADDR = 0x01; // This node's address

const uint8_t LORA_SERVER_ADDR = 0x00; // LoRa receiving address

const int WAIT_TIME = 3000; // ms

const int TX_BUF_SIZE = 8; // Transmit buffer size

const float RFM_FREQ = 915.0; // Frequency for RFM95W

const int RFM_TX_POWER = 17; // 5..23 dBm, 13 dBm is default


// Pins

// SPI:

// MOSI = 10

// MISO = 12

// SCK = 13

const int RFM_RST_PIN = 2;

const int RFM_INT_PIN = 3;

const int RFM_CS_PIN = 4;

const int BME_CS_PIN = 10;


// Instance of radio driver over SPI

RH_RF95 rfm(RFM_CS_PIN, RFM_INT_PIN);


// Communicate with BME280 over SPI

Adafruit_BME280 bme(BME_CS_PIN);


// Transmit buffer

uint8_t tx_bufTX_BUF_SIZE;


void setup() {


#if DEBUG

Serial.begin(9600);

#endif


// Manually reset RFM95W

pinMode(RFM_RST_PIN, OUTPUT);

digitalWrite(RFM_RST_PIN, HIGH);

delay(100);

digitalWrite(RFM_RST_PIN, LOW);

delay(10);

digitalWrite(RFM_RST_PIN, HIGH);

delay(10);


// Initialize RFM95W

if ( !rfm.init() ) {

#if DEBUG

Serial.println("Could not initialize RFM95");

#endif

while(1);

}

#if DEBUG

Serial.println("RFM95 initialized");

#endif


// Set RFM95W frequency

if ( !rfm.setFrequency(RFM_FREQ) ) {

#if DEBUG

Serial.println("Could not set frequency on RFM95");

#endif

while(1);

}

#if DEBUG

Serial.print("RFM95 frequency set to ");

Serial.print(RFM_FREQ);

Serial.print(" MHz");

#endif


// Set RFM95W transmit power from PA_BOOST pin

rfm.setTxPower(RFM_TX_POWER, false);


// Initialize BME280

if ( !bme.begin() ) {

#if DEBUG

Serial.println("Could not find BME280 on SPI bus");

#endif

while(1);

}

#if DEBUG

Serial.println("BME280 initialized");

#endif

}


void loop() {



// Read data

float temp = bme.readTemperature();

float humd = bme.readHumidity();

float pres = bme.readPressure() / 100.0;



// Scale (x10) and round data

int16_t tempt = (int16_t)((temp * 10.0) + 0.5);

int16_t humdt = (int16_t)((humd * 10.0) + 0.5);

int16_t prest = (int16_t)((pres * 10.0) + 0.5);


#if DEBUG

Serial.print("Temperature: ");

Serial.print(temp, 1);

Serial.println(" C");

Serial.print("Humidity: ");

Serial.print(humd, 1);

Serial.println("%");

Serial.print("Pressure: ");

Serial.print(pres, 1);

Serial.println(" hPa");

#endif



// Stuff buffer

tx_buf0 = LORA_NODE_ADDR; // From address (this node) 1 byte

tx_buf1 = LORA_SERVER_ADDR; // To address (server) 1 byte

tx_buf2 = (0xff & tempt); // Temperature 2 bytes little-endian

tx_buf3 = (0xff & (tempt >> 8));

tx_buf4 = (0xff & humdt); // Humidity 2 bytes little-endian

tx_buf5 = (0xff & (humdt >> 8));

tx_buf6 = (0xff & prest); // Pressure 2 bytes little-endian

tx_buf7 = (0xff & (prest >> 8));


#if DEBUG

Serial.print("Sending buffer:");

for ( int i = 0; i < TX_BUF_SIZE; i++) {

Serial.print(" 0x");

Serial.print(tx_bufi, HEX);

}

Serial.println();

Serial.println();

#endif


// Send data to server

rfm.send(tx_buf, TX_BUF_SIZE);

rfm.waitPacketSent();


delay(WAIT_TIME);

}


Server Code

Install Raspbian (with Desktop) on the Raspberry Pi. From a console, run the following command to install the RFM9x Python package:

Copy Code
pip install adafruit-circuitpython-rfm9x

Save the following code to a file and run it with Python:

Copy Code
# LoRa Weather Server
#
# Author: Shawn Hymel
# Date: March 23, 2019
#
# Receives and display temperature, humidity, and pressure data from raw LoRa
# radio. Run with lora-weather-client.ino on Arduino.
#
# Required packages:
# pip install adafruit-circuitpython-rfm9x
#
# License: Beerware

import time
import busio
from digitalio import DigitalInOut, Direction, Pull
import board
import adafruit_rfm9x

# Configure RFM9x LoRa Radio
CS = DigitalInOut(board.CE1)
RESET = DigitalInOut(board.D25)
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)

# Attempt to set up the RFM9x module
try:
rfm9x = adafruit_rfm9x.RFM9x(spi, CS, RESET, 915.0)
print('RFM9x detected')
except RuntimeError:
print('RFM9x error')


# Wait for LoRa packets
while True:
packet = None
packet = rfm9x.receive()
if packet != None:

print("Received:", str(packet))

# Split packet
from_addr = packet0
to_addr = packet1
temp = int.from_bytes(packet2:4, byteorder='little') / 10.0
humd = int.from_bytes(packet4:6, byteorder='little') / 10.0
pres = int.from_bytes(packet6:8, byteorder='little') / 10.0

# Print results
print("From:", from_addr)
print("To:", to_addr)
print("Temperature:", temp, "C")
print("Humidity:", humd, "%")
print("Pressure:", pres, "hPa")
print()

Running

The Arduino should begin sending temperature, humidity, and pressure data to the Raspberry Pi over the LoRa radio at regular intervals. Check the console on the Raspberry Pi to see the sensor output.

rpi-server-receiving

Repository

The whole project may be found in this repository, if you would like to view it, clone it, etc.: https://github.com/ShawnHymel/lora-weather

Arduino Project to Product Video series see the following:

Key Parts and Components

Add all Digi-Key Parts to Cart
  • 1050-1024-ND
  • 1528-1667-ND
  • PIS-1027-ND
  • 1528-1359-ND
  • 1690-1000-ND
  • 377-2094-ND
  • 1568-1512-ND