Skip to main content

pyLoraRFM9x

This project is a fork of raspi-lora project.

pyLoraRFM9x is a interrupt based Python library for using HopeRF RFM95/96/97/98 LoRa radios with a Raspberry Pi. The design was inspired by the RadioHead project that is popular on Arduino-based platforms. Several handy features offered by RadioHead are present here, including encryption, addressing, optional acknowledgments and retransmission. The motivation of this project is to allow Raspberry Pis to communicate with devices using the RadioHead RF95 driver.

This fork fixes bugs in the interrupt handling, and supports both acknowledged and unacknowledged transfers with the use of flags in the packet header.

Usage

Installation

Requires Python >= 3.5. lgpio and spidev will be installed as requirements

pip install --upgrade pyLoraRFM9x

Wiring

Example wiring for the HopeRF RFM95W and the Raspberry Pi:

RFM module pin Raspberry Pi GPIO pin
MISO MISO
MOSI MOSI
NSS/CS CE1
CLK SCK
RESET GPIO 25
DIO0 GPIO 5
3.3V 3.3V
GND GND

Remember to connect an antenna or a quarter wavelength wire to the RFM modules ANT pin.

Getting Started

First ensure that SPI is enabled on your Raspberry Pi:

sudo raspi-config

Go to 5 Interfacing Options, select P4 SPI and select Yes to enable.

Reboot and verify that you see two devices when writing

ls -l /dev/spidev*

in the terminal.

Next, here is a quick example that sets things up and sends a message:

from pyLoraRFM9x import LoRa, ModemConfig

# This is our callback function that runs when a message is received
def on_recv(payload):
    print("From:", payload.header_from)
    print("Received:", payload.message)
    print("RSSI: {}; SNR: {}".format(payload.rssi, payload.snr))

# Lora object will use spi port 0 and use chip select 1. GPIO pin 5 will be used for interrupts and set reset pin to 25
# The address of this device will be set to 2
lora = LoRa(0, 1, 5, 2, reset_pin = 25, modem_config=ModemConfig.Bw125Cr45Sf128, tx_power=14, acks=True)
lora.on_recv = on_recv

# Send a message to a recipient device with address 10
# Retry sending the message twice if we don't get an  acknowledgment from the recipient
message = "Hello there!"
status = lora.send_to_wait(message, 10, retries=2)
if status is True:
    print("Message sent!")
else:
    print("No acknowledgment from recipient")

Encryption

If you'd like to send and receive encrypted packets, you'll need to install the PyCrypto package. If you're working with devices running RadioHead with RHEncryptedDriver, I recommend using the AES cipher.

pip install pycrypto

and in your code:

from Crypto.Cipher import AES
crypto = AES.new("my-secret-encryption-key")

then pass in crypto when instantiating the LoRa object:

lora = LoRa(0, 17, 2, crypto=crypto)

Configuration

Initialization
LoRa(spi_channel, interrupt_pin, my_address, spi_port = 0, reset_pin=reset_pin, freq=915, tx_power=14,
      modem_config=ModemConfig.Bw125Cr45Sf128, acks=False, crypto=None)

spi_channel SPI channel to use (either 0 or 1, if your LoRa radio if connected to CE0 or CE1, respectively)

interrupt_pin GPIO pin (BCM-style numbering) to use for the interrupt

my_address The address number (0-254) your device will use when sending and receiving packets

**spi_port ** SPI port connected to module, 0 or 1

reset_pin The pin that resets the module. Defaults to None

freq Frequency used by your LoRa radio. Defaults to 915Mhz

tx_power Transmission power level from 5 to 23. Keep this as low as possible. Defaults to 14

model_config Modem configuration. See RadioHead docs. Default to Bw125Cr45Sf128.

acks If True, send an acknowledgment packet when a message is received and wait for an acknowledgment when transmitting a message. This is equivalent to using RadioHead's RHReliableDatagram

crypto An instance of PyCrypto Cipher.AES (see above example)

Other options:

A LoRa instance also has the following attributes that can be changed:

  • cad_timeout Timeout for channel activity detection. Default is 1 second
  • retry_timeout Time to wait for an acknowledgment before attempting a retry. Defaults to 0.5 seconds
  • wait_packet_sent_timeout Timeout for waiting for a packet to transmit. Default is 0.5 seconds
Methods
send_to_wait(data, header_to, header_flags=0)

Send a message and block until an acknowledgment is received or a timeout occurs. Returns True if successful

  • data Your message. Can be a string or byte string
  • header_to Address of recipient (0-255). If address is 255, the message will be broadcast to all devices and send_to_wait will return True without waiting for acknowledgments
  • header_flags Bitmask that can contain flags specific to your application
send(data, header_to, header_id=0, header_flags=0)

Similar to send_to_wait but does not block or wait for acknowledgments and will always return True

  • data Your message. Can be a string or byte string
  • header_id Unique ID of message (0-255)
  • header_to Address of recipient (0-255). If address is 255, the message will be broadcast to all devices
  • header_flags Bitmask that can contain flags specific to your application
set_mode_rx()

Set radio to RX continuous mode

set_mode_tx()

Set radio to TX mode

set_mode_idle()

Set radio to idle (disabling receiving or transmitting)

sleep()

Set radio to low-power sleep mode

wait_packet_sent()

Blocks until a packet has finished transmitting. Returns False if a timeout occurs

close()

Cleans up GPIO pins and closes the SPI connection. This should be called when your program exits.

Callbacks

on_recv(payload) Callback function that runs when a message is received payload has the following attributes: header_from, header_to, header_id, header_flags, message, rssi, snr

Verify pin usage

Use gpioinfo command in the shell

Resources

RadioHead - The RadioHead project. Very useful source of information on working with LoRa radios.

Forked version of RadioHead for Raspberry Pi - A fork of the original RadioHead project that better accommodates the Raspberry Pi. Currently is a few years out of date.

pySX127x - Another Python LoRa library that allows for a bit more configuration.

Adafruit CircuitPython module for the RFM95/6/7/8 - LoRa library for CircuitPython

Changelog

1.0.2

Typo fixed in error handling call

1.0.1

Added option to select SPI module

1.0.0

Removed RPi.GPIO dependency and ported to lgpio due to the removal of the sysfs GPIO interface in newer kernels

0.9.4

Fixed a timing issue that could cause the modem to hang when transmitting.

0.9.3

Removed unecessary numpy import

0.9.2

Merged martynwheeler's fix for handling ACKS, and straend's naming

Metadata

Release files for pyLoraRFM9x 1.0.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pyLoraRFM9x 1.0.2
File Size Uploaded Provenance Actions
pylorarfm9x-1.0.2.tar.gz 12.8 kB Without provenance Details for pylorarfm9x-1.0.2.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for pyLoraRFM9x 1.0.2
File Interpreter ABI Platform Actions
pyLoraRFM9x-1.0.2-py3-none-any.whl Python 3 none any Details for pyLoraRFM9x-1.0.2-py3-none-any.whl

Total release size: 24.3 kB

Release files / pylorarfm9x-1.0.2.tar.gz

Download URL pylorarfm9x-1.0.2.tar.gz
Size 12.8 kB
Tags Source
SHA-256 checksum
How to use checksums
9e7866aa3c837e0e7f689be3a510775ceba17b83044cd6b3584c94fc6625f5c4
BLAKE2b-256 checksum
How to use checksums
269ecbafe1202a69bd1cf5397481064061295a9ab5da3f7ed2c3a03f8f064d51
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/5.0.0 CPython/3.11.8

Release files / pyLoraRFM9x-1.0.2-py3-none-any.whl

Download URL pyLoraRFM9x-1.0.2-py3-none-any.whl
Size 11.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
04dfd58467c28da5a8f1afd17fdccd50df201d4b744b85535b35b61cffea9ca3
BLAKE2b-256 checksum
How to use checksums
b7bd400ba699c44e16a71ebff045abcbc224bab504139fc8203fc6ae997dd99d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/5.0.0 CPython/3.11.8

Security for pyLoraRFM9x 1.0.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page