Do not use this if you have a RFM69 Packet Radio, its for RFM9X radio's only!
pi_a___b___2__3_Lora_logo.png
LoRa Logo via lora-alliance.org

The RFM9x is a more expensive module than the RFM69, but it has a trick - LoRa. LoRa is a spread spectrum modulation technique patented by Semtech. It allows your packets to be sent over farther distances (a few km in a city like New York and around 40km in a rural area).

It's also a low power protocol with batteries lasting in the year range, instead of a few days with WiFi. This is made possible by only powering up the LoRa radio when packets are being sent, instead of keeping the radio always-on (like the WiFi radio on your cell phone).

When building a project which uses LoRa, keep in mind that only a few hundred bytes per-transmission can be sent, and that each transmission will cause the battery life to decrease.

If a LoRa project involves a lot of sensors, expect to cram a lot of data into a small packet which is transmitted infrequently.

RFM9x and CircuitPython

It's easy to use the RFM9x LoRa radio with CircuitPython and the Adafruit CircuitPython RFM9x module.  This module allows you to easily write Python code that sends and receives packets of data with the radio.  

Be careful to note this library is for the RFM9x (RFM95/96/97/98) Radio only and will not work with the RFM69.

To demonstrate how the RFM9x LoRa module sends packets, we'll build an example where we send and receive data between two radios.

CircuitPython Transmitter/Receiver Example

Below is an example of using the RFM9x to transmit, or receive from, another RFM9x radio. Save this as radio_rfm9x.py on your Raspberry Pi. 

# SPDX-FileCopyrightText: 2018 Brent Rubell for Adafruit Industries
#
# SPDX-License-Identifier: MIT

"""
Example for using the RFM9x Radio with Raspberry Pi.

Learn Guide: https://learn.adafruit.com/lora-and-lorawan-for-raspberry-pi
Author: Brent Rubell for Adafruit Industries
"""
# Import Python System Libraries
import time
# Import Blinka Libraries
import busio
from digitalio import DigitalInOut, Direction, Pull
import board
# Import the SSD1306 module.
import adafruit_ssd1306
# Import RFM9x
import adafruit_rfm9x

# Button A
btnA = DigitalInOut(board.D5)
btnA.direction = Direction.INPUT
btnA.pull = Pull.UP

# Button B
btnB = DigitalInOut(board.D6)
btnB.direction = Direction.INPUT
btnB.pull = Pull.UP

# Button C
btnC = DigitalInOut(board.D12)
btnC.direction = Direction.INPUT
btnC.pull = Pull.UP

# Create the I2C interface.
i2c = busio.I2C(board.SCL, board.SDA)

# 128x32 OLED Display
reset_pin = DigitalInOut(board.D4)
display = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c, reset=reset_pin)
# Clear the display.
display.fill(0)
display.show()
width = display.width
height = display.height

# Configure LoRa Radio
CS = DigitalInOut(board.CE1)
RESET = DigitalInOut(board.D25)
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
rfm9x = adafruit_rfm9x.RFM9x(spi, CS, RESET, 915.0)
rfm9x.tx_power = 23
prev_packet = None

while True:
    packet = None
    # draw a box to clear the image
    display.fill(0)
    display.text('RasPi LoRa', 35, 0, 1)

    # check for packet rx
    packet = rfm9x.receive()
    if packet is None:
        display.show()
        display.text('- Waiting for PKT -', 15, 20, 1)
    else:
        # Display the packet text and rssi
        display.fill(0)
        prev_packet = packet
        packet_text = str(prev_packet, "utf-8")
        display.text('RX: ', 0, 0, 1)
        display.text(packet_text, 25, 0, 1)
        time.sleep(1)

    if not btnA.value:
        # Send Button A
        display.fill(0)
        button_a_data = bytes("Button A!\r\n","utf-8")
        rfm9x.send(button_a_data)
        display.text('Sent Button A!', 25, 15, 1)
    elif not btnB.value:
        # Send Button B
        display.fill(0)
        button_b_data = bytes("Button B!\r\n","utf-8")
        rfm9x.send(button_b_data)
        display.text('Sent Button B!', 25, 15, 1)
    elif not btnC.value:
        # Send Button C
        display.fill(0)
        button_c_data = bytes("Button C!\r\n","utf-8")
        rfm9x.send(button_c_data)
        display.text('Sent Button C!', 25, 15, 1)


    display.show()
    time.sleep(0.1)

You'll also want to download the font file, font5x8.bin, and copy it into the same directory as the script:

To run the example, enter the following into the terminal:

python3 radio_rfm9x.py

Both of the radios will listen for a new incoming packet. When they receive a new packet, they'll print the text from the packet to the display (and to the terminal).

Press any of the three buttons to send data between radios. Pressing button a will send a packet with data 'Button A!' to the other radio, and so on!

This guide was first published on Jan 18, 2019. It was last updated on Jan 18, 2019.

This page (Sending Data with LoRa) was last updated on Oct 01, 2023.

Text editor powered by tinymce.