Giter VIP home page Giter VIP logo

adafruit_circuitpython_rfm69's Introduction

Introduction

Documentation Status

Discord

Build Status

Code Style: Black

CircuitPython RFM69 packet radio module. This supports basic RadioHead-compatible sending and receiving of packets with RFM69 series radios (433/915Mhz).

Warning

This is NOT for LoRa radios!

Note

This is a 'best effort' at receiving data using pure Python code--there is not interrupt support so you might lose packets if they're sent too quickly for the board to process them. You will have the most luck using this in simple low bandwidth scenarios like sending and receiving a 60 byte packet at a time--don't try to receive many kilobytes of data at a time!

Dependencies

This driver depends on:

Please ensure all dependencies are available on the CircuitPython filesystem. This is easily achieved by downloading the Adafruit library and driver bundle.

Installing from PyPI

On supported GNU/Linux systems like the Raspberry Pi, you can install the driver locally from PyPI. To install for current user:

pip3 install adafruit-circuitpython-rfm69

To install system-wide (this may be required in some cases):

sudo pip3 install adafruit-circuitpython-rfm69

To install in a virtual environment in your current project:

mkdir project-name && cd project-name
python3 -m venv .venv
source .venv/bin/activate
pip3 install adafruit-circuitpython-rfm69

Usage Example

See examples/rfm69_simpletest.py for a simple demo of the usage. Note: the default baudrate for the SPI is 2000000 (2MHz). The maximum setting is 10Mhz but transmission errors have been observed expecially when using breakout boards. For breakout boards or other configurations where the boards are separated, it may be necessary to reduce the baudrate for reliable data transmission. The baud rate may be specified as an keyword parameter when initializing the board. To set it to 1000000 use :

# Initialze RFM radio
rfm9x = adafruit_rfm9x.RFM9x(spi, CS, RESET, RADIO_FREQ_MHZ, baudrate=1000000)

Documentation

API documentation for this library can be found on Read the Docs.

For information on building library documentation, please check out this guide.

Contributing

Contributions are welcome! Please read our Code of Conduct before contributing to help this project stay welcoming.

adafruit_circuitpython_rfm69's People

Contributors

brennen avatar brentru avatar dhalbert avatar evaherrada avatar foamyguy avatar jerryneedell avatar kattni avatar ladyada avatar michaeldye avatar siddacious avatar sommersoft avatar tannewt avatar tcfranks avatar tdicola avatar tekktrik avatar vladak avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

adafruit_circuitpython_rfm69's Issues

Missing Type Annotations

There are missing type annotations for some functions in this library.

The typing module does not exist on CircuitPython devices so the import needs to be wrapped in try/except to catch the error for missing import. There is an example of how that is done here:

try:
    from typing import List, Tuple
except ImportError:
    pass

Once imported the typing annotations for the argument type(s), and return type(s) can be added to the function signature. Here is an example of a function that has had this done already:

def wrap_text_to_pixels(
    string: str, max_width: int, font=None, indent0: str = "", indent1: str = ""
) -> List[str]:

If you are new to Git or Github we have a guide about contributing to our projects here: https://learn.adafruit.com/contribute-to-circuitpython-with-git-and-github

There is also a guide that covers our CI utilities and how to run them locally to ensure they will pass in Github Actions here: https://learn.adafruit.com/creating-and-sharing-a-circuitpython-library/check-your-code In particular the pages: Sharing docs on ReadTheDocs and Check your code with pre-commit contain the tools to install and commands to run locally to run the checks.

If you are attempting to resolve this issue and need help, you can post a comment on this issue and tag both @FoamyGuy and @kattni or reach out to us on Discord: https://adafru.it/discord in the #circuitpython-dev channel.

The following locations are reported by mypy to be missing type annotations:

  • adafruit_rfm69.py:192
  • adafruit_rfm69.py:204
  • adafruit_rfm69.py:208
  • adafruit_rfm69.py:242
  • adafruit_rfm69.py:357
  • adafruit_rfm69.py:369
  • adafruit_rfm69.py:374
  • adafruit_rfm69.py:386
  • adafruit_rfm69.py:469
  • adafruit_rfm69.py:501
  • adafruit_rfm69.py:525
  • adafruit_rfm69.py:546
  • adafruit_rfm69.py:574
  • adafruit_rfm69.py:610
  • adafruit_rfm69.py:666
  • adafruit_rfm69.py:681
  • adafruit_rfm69.py:696
  • adafruit_rfm69.py:766
  • adafruit_rfm69.py:804

Frequency change does not work.

When the frequency is passed in to init it is incorrectly stored as
self.frequency
https://github.com/adafruit/Adafruit_CircuitPython_RFM69/blob/master/adafruit_rfm69.py#L343
but the actual "setter" is
self.frequnecy_mhz
https://github.com/adafruit/Adafruit_CircuitPython_RFM69/blob/master/adafruit_rfm69.py#L536
So that new frequency is not actually sent to the chip.

This is a similar issue found in the rfm9x driver and fixed there via adafruit/Adafruit_CircuitPython_RFM9x#4 . There were a few additional issues found in that may also be appropriate for this driver.

Posted in response to Forum post https://forums.adafruit.com/viewtopic.php?f=8&t=135989&p=674098#p674098

The default setting of 915 Mhz is in section 6.2 table 24 of the data sheet https://cdn-shop.adafruit.com/product-files/3076/RFM69HCW-V1.1.pdf

whereas the RFM9x defaults to 433Mhz - see section 6.1 table 85
https://cdn-learn.adafruit.com/assets/assets/000/031/659/original/RFM95_96_97_98W.pdf?1460518717

RSSI values wrong

I have two radios sitting side by side with antenna. one runs M0 with C code and returns -23 to -26 when reporting RSSI

the M4 with featherwing reports -87.5 to -90.5.

100 ft away through 4 walls, arduino reports -56, and Python reports same -90.5 as before.

clarify use of flags

the flags byte of the packet header may contain user data in the low 4 bits.
receive() does not save the flags in self.flags so they cannot be read easily.
They can be extracted from the header, but only if the header is saved, which is not the default.
receive could save the 4th but of the packet heard in self.flags.
This may cause problems tough because self.flags is also used by send()
If receive() updates self.flags then the next send will use the same self.flags settings -- this is not what is wanted.

Perhaps this is not really a bug, but just needs to be clarified in the documentation.

If a user wants to set the flags byte of the header, then the receiver must save and pars the header to find the flags.
The sender can use rfm69.flags to set the flags, but the receiver cannot read the flags via rfm69.flags. They can only be read via the header.

Send and recieved commands freeze

Hi,
Any send or recieve command I make can run for hours and when I've decided to stop them this occure:

File "rfm69_simpletest.py", line 50, in <module> rfm69.send(bytes('Hello world!\r\n',"utf-8")) File "/usr/local/lib/python3.5/dist-packages/adafruit_circuitpython_rfm69-1.2.5-py3.5.egg/adafruit_rfm69.py", line 695, in send File "/usr/local/lib/python3.5/dist-packages/adafruit_circuitpython_rfm69-1.2.5-py3.5.egg/adafruit_rfm69.py", line 403, in idle File "/usr/local/lib/python3.5/dist-packages/adafruit_circuitpython_rfm69-1.2.5-py3.5.egg/adafruit_rfm69.py", line 471, in operation_mode File "/usr/local/lib/python3.5/dist-packages/adafruit_circuitpython_rfm69-1.2.5-py3.5.egg/adafruit_rfm69.py", line 223, in __get__ File "/usr/local/lib/python3.5/dist-packages/adafruit_circuitpython_rfm69-1.2.5-py3.5.egg/adafruit_rfm69.py", line 365, in _read_u8 File "/usr/local/lib/python3.5/dist-packages/adafruit_circuitpython_rfm69-1.2.5-py3.5.egg/adafruit_rfm69.py", line 357, in _read_into File "/usr/local/lib/python3.5/dist-packages/adafruit_circuitpython_busdevice-2.2.9-py3.5.egg/adafruit_bus_device/spi_device.py", line 83, in __enter__ File "/usr/local/lib/python3.5/dist-packages/Adafruit_Blinka-1.2.8-py3.5.egg/busio.py", line 93, in configure if detector.board.any_raspberry_pi: File "/usr/local/lib/python3.5/dist-packages/Adafruit_PlatformDetect-1.0.0-py3.5.egg/adafruit_platformdetect/board.py", line 351, in any_raspberry_pi File "/usr/local/lib/python3.5/dist-packages/Adafruit_PlatformDetect-1.0.0-py3.5.egg/adafruit_platformdetect/board.py", line 295, in _pi_rev_code File "/usr/local/lib/python3.5/dist-packages/Adafruit_PlatformDetect-1.0.0-py3.5.egg/adafruit_platformdetect/chip.py", line 62, in id File "/usr/local/lib/python3.5/dist-packages/Adafruit_PlatformDetect-1.0.0-py3.5.egg/adafruit_platformdetect/chip.py", line 77, in _linux_id File "/usr/local/lib/python3.5/dist-packages/Adafruit_PlatformDetect-1.0.0-py3.5.egg/adafruit_platformdetect/__init__.py", line 52, in get_cpuinfo_field File "/usr/lib/python3.5/re.py", line 173, in search return _compile(pattern, flags).search(string) KeyboardInterrupt

Feather RP2040 RFM69 Packet Radio version 35 not supported

A recently-purchased feather has an rfm69 device that reports version 0x23 which fails a version check in the RFM69 constructor:

...
  File "/lib/adafruit_rfm69.py", line 316, in __init__
RuntimeError: Invalid RFM69 version, check wiring!

Version number extraction from REPL:

import time
import board
import digitalio
import adafruit_bus_device.spi_device as spidev
from micropython import const

reset = digitalio.DigitalInOut(board.RFM_RST)
reset.switch_to_output(value=False)
reset.value = True
time.sleep(0.0001)
reset.value = False
time.sleep(0.005)

buff = bytearray(4)
dev = spidev.SPIDevice(board.SPI(), digitalio.DigitalInOut(board.RFM_CS), baudrate=2000000, polarity=0, phase=0)
with dev as d:
  buff[0] = const(0x10) & 0x7f
  d.write(buff, end=1)
  d.readinto(buff, end=4)


print(f"{buff[0]:#0x}")

Listen() versus Receive()

Hi,

I need to listen permanently on incoming packets. Doing that by receive() (ex. "while not None") the CPU goes nearly 100%.
Pull the listen function incoming packets automatically into the buffer? Is there any chance to check that (new packets are in the buffer= True), instead of permanently looping the receive function ?

Allow access to RadioHead packet headers

I think it would be useful to allow the user to set/read the contents of the RadioHead Packet header:

To
From
ID
Flags

so multiple radios can distinguish source/recipient

I'm not sure we need the full Reliable Datagram protocol but can start with just providing access to the headers. Now they are discarded on read and set to Broadcast on send.

Would you like to see this added to the library? If so, I'll implement it here first then add it to the RF9x as well.

SPI baud rate too high for breakout board

When using the RFM69HCW breakout board, I was getting and error that the board version was incorrect.

Failed to find RFM69 with expected version, check wiring!

I put a print statement in the lib and found that it was returning a 0x10 not the expected 0x24

Note - it works fine fine with an RFM69HCW Featherwing

with help from @sommersoft
It appears that this is due to a garbled read of the board version register.

Lowering the SPI baud rate from 10000000 to 9000000 appears to have fixed the problem.
https://github.com/adafruit/Adafruit_CircuitPython_RFM69/blob/1abb4f7ce6fa5513c4e9c7dc280c1c2c28a7d062/adafruit_rfm69.py#L267

Presumably this is due to the longer jumper wires when using the breakout.
I'm not sure what the best fix is for this.

Perhaps allowing the baud rates as an input parameter with a warning for breakout board users.

standard python and interrupt - update documentation

this library works very well (little modification) in conjunction with python3 on a raspberry, a Adafruit RFM69 breakout board and the interrupt feature (DIO0). In my case, the raspberry work as a bridge between a RFM69-network and LAN.

To use this:
io.setup(self.dio0_pin, io.IN,pull_up_down=io.PUD_DOWN)

and

io.add_event_detect(self.dio0_pin, io.RISING, callback = the_script_to_handle_the data)

maybe people are interested in this.

RuntimeError: Timeout during packet send

I have been working with the RFM69 radio modules and the associated Circuitpython library. There is a RuntimeError: Timeout during packet send generated when the send function times out. The library source for this function states that the timeout is only there to prevent hang.

This is fine, but why does there have to be a runtime error generated when this happens?

I propose we not generate an error on this condition.

address a server

to prevent useless communication, I used "rx_filter" to address data packets to a correct destination, the server just listening on packets designated for his own address. Now is see, "rx_filter" was deleted. Why?

Implement "Reliable Datagram"

The Radiohead library has a "Reliable Datagram" mode that uses acknowledgement and retries to insure packet delivery.

Is there interest in implementing that here. I'll be happy to take it on, but wanted to see if there was any concern or interest.

question: receive function

I use python on raspberry and c++ on a mcu. The mcu use the RHReliableDatagram library. Each time, I send a packet from the raspberry to the mcu, the python receive function returns (via log) a packet with 12 byte 0x00. Is that the "ACK part" of the the reliable library?

Can receive from Radiohead with different modem config, but it is unable to receive back from this library

In the following code you can see I am changing the

rfm69.bitrate = 2400
rfm69.preamble_length = 3
rfm69.frequency_deviation = 4800  # 4.8khz

This works to match the modem config of the RadioHead Arduino library for receiving from that device, but when it comes to sending, the packets only get sent if I keep the default 250/250 settings making me thing there is something I need to do on the circuit python side to set the modem config registers the same, but it is not clear how.

# SPDX-FileCopyrightText: 2018 Tony DiCola for Adafruit Industries
# SPDX-License-Identifier: MIT

# Simple example to send a message and then wait indefinitely for messages
# to be received.  This uses the default RadioHead compatible GFSK_Rb250_Fd250
# modulation and packet format for the radio.
import board
import busio
import digitalio
import time
import adafruit_rfm69
from neopixel import NeoPixel
 
num_pixels = 24
pixels = NeoPixel(board.GP16, num_pixels)
pixels.brightness = 0.5


def wheel(pos):
    # Input a value 0 to 255 to get a color value.
    # The colours are a transition r - g - b - back to r.
    if pos < 0 or pos > 255:
        r = g = b = 0
    elif pos < 85:
        r = int(pos * 3)
        g = int(255 - pos * 3)
        b = 0
    elif pos < 170:
        pos -= 85
        r = int(255 - pos * 3)
        g = 0
        b = int(pos * 3)
    else:
        pos -= 170
        r = 0
        g = int(pos * 3)
        b = int(255 - pos * 3)
    return (r, g, b)


def rainbow_cycle(wait):
    pixels.brightness = 1
    for i in range(num_pixels):
        pixel_index = (i * 256 // num_pixels)
        pixels[i] = wheel(pixel_index & 255)
    pixels.show()
    time.sleep(wait)
    pixels.brightness = 0
    pixels.show()


# Define radio parameters.
RADIO_FREQ_MHZ = 915.0  # Frequency of the radio in Mhz. Must match your
# module! Can be a value like 915.0, 433.0, etc.

# Define pins connected to the chip, use these if wiring up the breakout according to the guide:
CS = digitalio.DigitalInOut(board.GP5)
RESET = digitalio.DigitalInOut(board.GP27)

# Initialize SPI bus.
spi = busio.SPI(board.GP2, MOSI=board.GP3, MISO=board.GP4)

time.sleep(1.0)

# Initialze RFM radio
rfm69 = adafruit_rfm69.RFM69(spi, CS, RESET, RADIO_FREQ_MHZ, baudrate=1000000)
rfm69.bitrate = 2400
rfm69.preamble_length = 3
rfm69.frequency_deviation = 4800  # 4.8khz
rfm69.tx_power = 20
print(rfm69.bitrate)
print(rfm69.frequency_deviation)
print(rfm69.tx_power)

# Optionally set an encryption key (16 byte AES key). MUST match both
# on the transmitter and receiver (or be set to None to disable/the default).
# REDACTED

# Print out some chip state:
print("Temperature: {0}C".format(rfm69.temperature))
print("Frequency: {0}mhz".format(rfm69.frequency_mhz))
print("Bit rate: {0}kbit/s".format(rfm69.bitrate / 1000))
print("Frequency deviation: {0}hz".format(rfm69.frequency_deviation))

# Send a packet.  Note you can only send a packet up to 60 bytes in length.
# This is a limitation of the radio packet size, so if you need to send larger
# amounts of data you will need to break it into smaller send calls.  Each send
# call will wait for the previous one to finish before continuing.
#rfm69.send(bytes("Hello world!\r\n", "utf-8"))
#print("Sent hello world message!")

# Wait to receive packets.  Note that this library can't receive data at a fast
# rate, in fact it can only receive and process one 60 byte packet at a time.
# This means you should only use this for low bandwidth scenarios, like sending
# and receiving a single message at a time.
print("Waiting for packets...")             
while True:
    packet = rfm69.receive()
    # Optionally change the receive timeout from its default of 0.5 seconds:
    # packet = rfm69.receive(timeout=5.0)
    # If no packet was received during the timeout then None is returned.
    if packet is None:
        # Packet has not been received
        # print("Received nothing! Listening again...")
        pass
    else:
        # Received a packet!
        # Print out the raw bytes of the packet:
        t = time.time()
        print("Received at {0} (raw bytes): {1}".format(t, packet))
        print(rfm69.rssi)
        # And decode to ASCII text and print it too.  Note that you always
        # receive raw bytes and need to convert to a text format like ASCII
        # if you intend to do string processing on your data.  Make sure the
        # sending side is sending ASCII data before you try to decode!
        try:
            time.sleep(.5)
            packet_text = str(packet, "ascii")
            print("Received at {0} (ASCII): {1}".format(t, packet_text))
            if "Mail Recieved" in packet_text:
                print("Send Ack")
                print(rfm69.transmit())
                print(rfm69.send(bytes("Ack", "utf-8"), keep_listening=True))
                print(rfm69.packet_sent())
                rainbow_cycle(2.0)
            time.sleep(1.0)
        except:
            pass

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.