pyLoraRFM9x


NamepyLoraRFM9x JSON
Version 1.0.2 PyPI version JSON
download
home_pageNone
SummaryInterrupt driven LoRa RFM9x library for Raspberry Pi inspired by RadioHead
upload_time2024-04-13 20:53:38
maintainerNone
docs_urlNone
authorNone
requires_python>=3.5
licenseMIT License Copyright (c) 2019 Anne Wood, 2020 Edwin G.W. Peters Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keywords lora rfm95 rfm9x rfm96 rfm97 rfm98 hardware raspberrypi
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # pyLoraRFM9x

This project is a fork of [raspi-lora](https://gitlab.com/the-plant/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](http://www.airspayce.com/mikem/arduino/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](http://www.airspayce.com/mikem/arduino/RadioHead/classRH__RF95.html) 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](http://abyz.me.uk/lg/py_lgpio.html) and [spidev](https://pypi.python.org/pypi/spidev) will be installed as requirements
```bash
pip install --upgrade pyLoraRFM9x
```

### Wiring
Example wiring for the [HopeRF RFM95W](https://www.hoperf.com/modules/lora/RFM95.html) 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:
```bash
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
```bash
ls -l /dev/spidev*
```
in the terminal.

Next, here is a quick example that sets things up and sends a message:
```python
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](https://www.dlitz.net/software/pycrypto/) package. If you're working with devices running RadioHead with RHEncryptedDriver, I recommend using the AES cipher.
```bash
pip install pycrypto
```

and in your code:
```python
from Crypto.Cipher import AES
crypto = AES.new("my-secret-encryption-key")
```
then pass in `crypto` when instantiating the `LoRa` object:
```python
lora = LoRa(0, 17, 2, crypto=crypto)
```

### Configuration
##### Initialization
```python
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](http://www.airspayce.com/mikem/arduino/RadioHead/classRH__RF95.html#ab9605810c11c025758ea91b2813666e3). 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](https://www.dlitz.net/software/pycrypto/api/current/Crypto.Cipher.AES-module.html) (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](http://www.airspayce.com/mikem/arduino/RadioHead/) - The RadioHead project. Very useful source of information on working with LoRa radios.

[Forked version of RadioHead for Raspberry Pi](https://github.com/hallard/RadioHead) - A fork of the original RadioHead project that better accommodates the Raspberry Pi. Currently is a few years out of date.

[pySX127x](https://github.com/mayeranalytics/pySX127x) - Another Python LoRa library that allows for a bit more configuration. 

[Adafruit CircuitPython module for the RFM95/6/7/8](https://github.com/adafruit/Adafruit_CircuitPython_RFM9x) - 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


            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "pyLoraRFM9x",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.5",
    "maintainer_email": null,
    "keywords": "lora, rfm95, rfm9x, rfm96, rfm97, rfm98, hardware, raspberrypi",
    "author": null,
    "author_email": "Edwin Peters <edwin.g.w.peters@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/26/9e/cbafe1202a69bd1cf5397481064061295a9ab5da3f7ed2c3a03f8f064d51/pylorarfm9x-1.0.2.tar.gz",
    "platform": null,
    "description": "# pyLoraRFM9x\n\nThis project is a fork of [raspi-lora](https://gitlab.com/the-plant/raspi-lora) project.\n\npyLoraRFM9x 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](http://www.airspayce.com/mikem/arduino/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](http://www.airspayce.com/mikem/arduino/RadioHead/classRH__RF95.html) driver.\n\nThis fork fixes bugs in the interrupt handling, and supports both acknowledged and unacknowledged transfers with the use of flags in the packet header.\n\n# Usage\n### Installation\nRequires Python >= 3.5. [lgpio](http://abyz.me.uk/lg/py_lgpio.html) and [spidev](https://pypi.python.org/pypi/spidev) will be installed as requirements\n```bash\npip install --upgrade pyLoraRFM9x\n```\n\n### Wiring\nExample wiring for the [HopeRF RFM95W](https://www.hoperf.com/modules/lora/RFM95.html) and the Raspberry Pi:\n\n| RFM module pin    | Raspberry Pi GPIO pin|\n|:-----------------:|:--------------------:|\n| MISO              | MISO                 |\n| MOSI              | MOSI                 |\n| NSS/CS            | CE1                  |\n| CLK               | SCK                  |\n| RESET             | GPIO 25              |\n| DIO0              | GPIO 5               |   \n| 3.3V              | 3.3V                 |\n| GND               | GND                  |\n\nRemember to connect an antenna or a quarter wavelength wire to the RFM modules ANT pin.\n\n### Getting Started\nFirst ensure that SPI is enabled on your Raspberry Pi:\n```bash\nsudo raspi-config\n```\nGo to **5 Interfacing Options**, select **P4 SPI** and select **Yes** to enable.\n\nReboot and verify that you see two devices when writing\n```bash\nls -l /dev/spidev*\n```\nin the terminal.\n\nNext, here is a quick example that sets things up and sends a message:\n```python\nfrom pyLoraRFM9x import LoRa, ModemConfig\n\n# This is our callback function that runs when a message is received\ndef on_recv(payload):\n    print(\"From:\", payload.header_from)\n    print(\"Received:\", payload.message)\n    print(\"RSSI: {}; SNR: {}\".format(payload.rssi, payload.snr))\n\n# 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\n# The address of this device will be set to 2\nlora = LoRa(0, 1, 5, 2, reset_pin = 25, modem_config=ModemConfig.Bw125Cr45Sf128, tx_power=14, acks=True)\nlora.on_recv = on_recv\n\n# Send a message to a recipient device with address 10\n# Retry sending the message twice if we don't get an  acknowledgment from the recipient\nmessage = \"Hello there!\"\nstatus = lora.send_to_wait(message, 10, retries=2)\nif status is True:\n    print(\"Message sent!\")\nelse:\n    print(\"No acknowledgment from recipient\")\n```\n\n### Encryption\nIf you'd like to send and receive encrypted packets, you'll need to install the [PyCrypto](https://www.dlitz.net/software/pycrypto/) package. If you're working with devices running RadioHead with RHEncryptedDriver, I recommend using the AES cipher.\n```bash\npip install pycrypto\n```\n\nand in your code:\n```python\nfrom Crypto.Cipher import AES\ncrypto = AES.new(\"my-secret-encryption-key\")\n```\nthen pass in `crypto` when instantiating the `LoRa` object:\n```python\nlora = LoRa(0, 17, 2, crypto=crypto)\n```\n\n### Configuration\n##### Initialization\n```python\nLoRa(spi_channel, interrupt_pin, my_address, spi_port = 0, reset_pin=reset_pin, freq=915, tx_power=14,\n      modem_config=ModemConfig.Bw125Cr45Sf128, acks=False, crypto=None)\n```\n**`spi_channel`** SPI channel to use (either 0 or 1, if your LoRa radio if connected to CE0 or CE1, respectively)\n\n**`interrupt_pin`** GPIO pin (BCM-style numbering) to use for the interrupt\n\n**`my_address`** The address number (0-254) your device will use when sending and receiving packets\n\n**`spi_port` ** SPI port connected to module, 0 or 1\n\n**`reset_pin`** The pin that resets the module. Defaults to None\n\n**`freq`** Frequency used by your LoRa radio. Defaults to 915Mhz\n\n**`tx_power`** Transmission power level from 5 to 23. Keep this as low as possible. Defaults to 14\n\n**`model_config`** Modem configuration. See [RadioHead docs](http://www.airspayce.com/mikem/arduino/RadioHead/classRH__RF95.html#ab9605810c11c025758ea91b2813666e3). Default to Bw125Cr45Sf128.\n\n**`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\n\n**`crypto`** An instance of [PyCrypto Cipher.AES](https://www.dlitz.net/software/pycrypto/api/current/Crypto.Cipher.AES-module.html) (see above example)\n\n\n##### Other options:\nA `LoRa` instance also has the following attributes that can be changed:\n- **cad_timeout** Timeout for channel activity detection. Default is 1 second\n- **retry_timeout** Time to wait for an acknowledgment before attempting a retry. Defaults to 0.5 seconds\n- **wait_packet_sent_timeout** Timeout for waiting for a packet to transmit. Default is 0.5 seconds\n\n##### Methods\n###### `send_to_wait(data, header_to, header_flags=0)`\nSend a message and block until an acknowledgment is received or a timeout occurs. Returns `True` if successful\n- ``data`` Your message. Can be a string or byte string\n- ``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\n- ``header_flags`` Bitmask that can contain flags specific to your application\n\n###### `send(data, header_to, header_id=0, header_flags=0)`\nSimilar to `send_to_wait` but does not block or wait for acknowledgments and will always return `True`\n- ``data`` Your message. Can be a string or byte string\n- ``header_id`` Unique ID of message (0-255)\n- ``header_to`` Address of recipient (0-255). If address is 255, the message will be broadcast to all devices\n- ``header_flags`` Bitmask that can contain flags specific to your application\n\n###### `set_mode_rx()`\nSet radio to RX continuous mode\n\n###### `set_mode_tx()`\nSet radio to TX mode\n\n###### `set_mode_idle()`\nSet radio to idle (disabling receiving or transmitting)\n\n###### `sleep()`\nSet radio to low-power sleep mode\n\n###### `wait_packet_sent()`\nBlocks until a packet has finished transmitting. Returns `False` if a timeout occurs\n\n###### `close()`\nCleans up GPIO pins and closes the SPI connection. This should be called when your program exits.\n\n##### Callbacks\n`on_recv(payload)` \nCallback function that runs when a message is received\n`payload` has the following attributes:\n`header_from`, `header_to`, `header_id`, `header_flags`, `message`, `rssi`, `snr`\n\n### Verify pin usage\nUse `gpioinfo` command in the shell\n\n# Resources\n[RadioHead](http://www.airspayce.com/mikem/arduino/RadioHead/) - The RadioHead project. Very useful source of information on working with LoRa radios.\n\n[Forked version of RadioHead for Raspberry Pi](https://github.com/hallard/RadioHead) - A fork of the original RadioHead project that better accommodates the Raspberry Pi. Currently is a few years out of date.\n\n[pySX127x](https://github.com/mayeranalytics/pySX127x) - Another Python LoRa library that allows for a bit more configuration. \n\n[Adafruit CircuitPython module for the RFM95/6/7/8](https://github.com/adafruit/Adafruit_CircuitPython_RFM9x) - LoRa library for CircuitPython\n\n# Changelog\n\n## 1.0.2\nTypo fixed in error handling call\n\n## 1.0.1\nAdded option to select SPI module\n\n## 1.0.0\nRemoved RPi.GPIO dependency and ported to lgpio due to the removal of the sysfs GPIO interface in newer kernels\n\n## 0.9.4\nFixed a timing issue that could cause the modem to hang when transmitting.\n\n## 0.9.3\nRemoved unecessary numpy import\n\n## 0.9.2\nMerged martynwheeler's fix for handling ACKS, and  straend's naming\n\n",
    "bugtrack_url": null,
    "license": "MIT License  Copyright (c) 2019 Anne Wood, 2020 Edwin G.W. Peters  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ",
    "summary": "Interrupt driven LoRa RFM9x library for Raspberry Pi inspired by RadioHead",
    "version": "1.0.2",
    "project_urls": {
        "Homepage": "https://github.com/epeters13/pyLoraRFM9x",
        "Issues": "https://github.com/epeters13/pyLoraRFM9x/issues"
    },
    "split_keywords": [
        "lora",
        " rfm95",
        " rfm9x",
        " rfm96",
        " rfm97",
        " rfm98",
        " hardware",
        " raspberrypi"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "b7bd400ba699c44e16a71ebff045abcbc224bab504139fc8203fc6ae997dd99d",
                "md5": "fc080d73bec9f3ca50f1b034af13daeb",
                "sha256": "04dfd58467c28da5a8f1afd17fdccd50df201d4b744b85535b35b61cffea9ca3"
            },
            "downloads": -1,
            "filename": "pyLoraRFM9x-1.0.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "fc080d73bec9f3ca50f1b034af13daeb",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.5",
            "size": 11474,
            "upload_time": "2024-04-13T20:53:34",
            "upload_time_iso_8601": "2024-04-13T20:53:34.463277Z",
            "url": "https://files.pythonhosted.org/packages/b7/bd/400ba699c44e16a71ebff045abcbc224bab504139fc8203fc6ae997dd99d/pyLoraRFM9x-1.0.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "269ecbafe1202a69bd1cf5397481064061295a9ab5da3f7ed2c3a03f8f064d51",
                "md5": "3a8beef7c7a02a260a1404e346150634",
                "sha256": "9e7866aa3c837e0e7f689be3a510775ceba17b83044cd6b3584c94fc6625f5c4"
            },
            "downloads": -1,
            "filename": "pylorarfm9x-1.0.2.tar.gz",
            "has_sig": false,
            "md5_digest": "3a8beef7c7a02a260a1404e346150634",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.5",
            "size": 12801,
            "upload_time": "2024-04-13T20:53:38",
            "upload_time_iso_8601": "2024-04-13T20:53:38.522562Z",
            "url": "https://files.pythonhosted.org/packages/26/9e/cbafe1202a69bd1cf5397481064061295a9ab5da3f7ed2c3a03f8f064d51/pylorarfm9x-1.0.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-04-13 20:53:38",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "epeters13",
    "github_project": "pyLoraRFM9x",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "pylorarfm9x"
}
        
Elapsed time: 0.22541s