Table of Contents

Getting Started

This is a Circuitpython driver library for the nRF24L01(+) transceiver.

Originally this code was a Micropython module written by Damien P. George & Peter Hinch which can still be found here

The Micropython source has since been rewritten to expose all the nRF24L01’s features and for Circuitpython compatible devices (including linux-based SoC computers like the Raspberry Pi). Modified by Brendan Doherty & Rhys Thomas.

  • Authors: Damien P. George, Peter Hinch, Rhys Thomas, Brendan Doherty

Features currently supported

  • Change the address’s length (can be 3 to 5 bytes long)
  • Dynamically sized payloads (max 32 bytes each) or statically sized payloads
  • Automatic responding acknowledgment (ACK) packets for verifying transmission success
  • Append custom payloadsto the acknowledgment (ACK) packets for instant bi-directional communication
  • Mark a single payload for no acknowledgment (ACK) from the receiving nRF24L01 (see ask_no_ack parameter for send() and write() functions)
  • Invoke the “re-use the same payload” feature (for manually re-transmitting failed transmissions that remain in the TX FIFO buffer)
  • Multiple payload transmissions with one function call (see documentation on the send() function and try out the Stream example)
  • Context manager compatible for easily switching between different radio configurations using The with statement blocks (not available in rf24_lite.py version)
  • Configure the interrupt (IRQ) pin to trigger (active low) on received, sent, and/or failed transmissions (these 3 events control 1 IRQ pin). There’s also virtual representations of these interrupt events available (see irq_dr, irq_ds, & irq_df attributes)
  • Invoke sleep mode (AKA power down mode) for ultra-low current consumption
  • cyclic redundancy checking (CRC) up to 2 bytes long
  • Adjust the nRF24L01’s builtin automatic re-transmit feature’s parameters (arc: number of attempts, ard: delay between attempts)
  • Adjust the nRF24L01’s frequency channel (2.4-2.525 GHz)
  • Adjust the nRF24L01’s power amplifier level (0, -6, -12, or -18 dBm)
  • Adjust the nRF24L01’s RF data rate (250kbps, 1Mbps, or 2Mbps)
  • An nRF24L01 driven by this library can communicate with a nRF24L01 on an Arduino driven by the TMRh20 RF24 library. See the nrf24l01_2arduino_handling_data.py example.
  • fake BLE module for sending BLE beacon advertisments from the nRF24L01 as outlined by Dmitry Grinberg in his write-up (including C source code).
  • MulticeiverTM mode (up to 6 TX nRF24L01 “talking” to 1 RX nRF24L01 simultaneously). See the Multiceiver Example

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.

Note

This library supports Python 3.4 or newer, but Python 3.7 introduced the function time.monotonic_ns() which returns an arbitrary time “counter” as an int of nanoseconds. However, this function is not used in the example scripts for backward compatibility reasons. Instead, we used monotonic() which returns an arbitrary time “counter” as a float of seconds. CircuitPython firmware supports both functions as of v4.0.

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 circuitpython-nrf24l01

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

sudo pip3 install circuitpython-nrf24l01

To install in a virtual environment in your current project:

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

Pinout

https://lastminuteengineers.com/wp-content/uploads/2018/07/Pinout-nRF24L01-Wireless-Transceiver-Module.png

The nRF24L01 is controlled through SPI so there are 3 pins (SCK, MOSI, & MISO) that can only be connected to their counterparts on the MCU (microcontroller unit). The other 2 essential pins (CE & CSN) can be connected to any digital output pins. Lastly, the only optional pin on the nRf24L01 GPIOs is the IRQ (interrupt; a digital output that’s active when low) pin and is only connected to the MCU via a digital input pin during the interrupt example. The following pinout is used in the example codes of this library’s example directory.

nRF2401 Raspberry Pi ItsyBitsy M4
GND GND GND
VCC 3V 3.3V
CE GPIO4 D4
CSN GPIO5 D5
SCK GPIO11 (SCK) SCK
MOSI GPIO10 (MOSI) MOSI
MISO GPIO9 (MISO) MISO
IRQ GPIO12 D12

Tip

User reports and personal experiences have improved results if there is a capacitor of 100 mirofarads [+ another optional 0.1 microfarads capacitor for added stability] connected in parrallel to the VCC and GND pins.

Using The Examples

See examples for testing certain features of this the library. The examples were developed and tested on both Raspberry Pi and ItsyBitsy M4. Pins have been hard coded in the examples for the corresponding device, so please adjust these accordingly to your circuitpython device if necessary.

To run the simple example, navigate to this repository’s “examples” folder in the terminal. If you’re working with a CircuitPython device (not a Raspberry Pi), copy the file named “nrf24l01_simple_test.py” from this repository’s “examples” folder to the root directory of your CircuitPython device’s CIRCUITPY drive. Now you’re ready to open a python REPR and run the following commands:

>>> from nrf24l01_simple_test import *
    nRF24L01 Simple test.
    Run slave() on receiver
    Run master() on transmitter
>>> master()
Sending: 5 as struct: b'\x05\x00\x00\x00'
send() successful
Transmission took 36.0 ms
Sending: 4 as struct: b'\x04\x00\x00\x00'
send() successful
Transmission took 28.0 ms
Sending: 3 as struct: b'\x03\x00\x00\x00'
send() successful
Transmission took 24.0 ms

What to purchase

See the store links on the sidebar or just google “nRF24L01+”. It is worth noting that you generally want to buy more than 1 as you need 2 for testing – 1 to send & 1 to receive and vise versa. This library has been tested on a cheaply bought 6 pack from Amazon.com, but don’t take Amazon or eBay for granted! There are other wireless transceivers that are NOT compatible with this library. For instance, the esp8266-01 (also sold in packs) is NOT compatible with this library, but looks very similar to the nRF24L01+ and could lead to an accidental purchase.

Power Stability

If you’re not using a dedicated 3V regulator to supply power to the nRF24L01, then adding capcitor(s) (100 µF + an optional 0.1µF) in parrellel (& as close as possible) to the VCC and GND pins is highly recommended. Stablizing the power input provides significant performance increases. More finite details about the nRF24L01 are available from the datasheet (referenced here in the documentation as the nRF24L01+ Specification Sheet)

About the nRF24L01+PA+LNA modules

You may find variants of the nRF24L01 transceiver that are marketed as “nRF24L01+PA+LNA”. These modules are distinct in the fact that they come with a detachable (SMA-type) antenna. They employ seperate RFX24C01 IC with the antenna for enhanced Power Amplification (PA) and Low Noise Amplification (LNA) features. While they boast greater range with the same functionality, they are subject to a couple lesser known (and lesser advertised) drawbacks:

  1. Stronger power source. Below is a chart of advertised current requirements that many MCU boards’ 3V regulators may not be able to provide (after supplying power to internal components).

    Specification Value
    Emission mode current(peak) 115 mA
    Receive Mode current(peak) 45 mA
    Power-down mode current 4.2 µA
  2. Needs shielding from electromagnetic interference. Shielding usually works best when it has a path to ground (GND pin), but this connection to the GND pin is not required.

See also the Testing nRF24L01+PA+LNA module

nRF24L01(+) clones and counterfeits

This library does not directly support clones/counterfeits as there is no way for the library to differentiate between an actual nRF24L01+ and a clone/counterfeit. To determine if your purchase is a counterfeit, please contact the retailer you purchased from (also reading this article and its links might help). The most notable clone is the Si24R1. I could not find the Si24R1 datasheet in english. Troubleshooting the SI24R1 may require replacing the onboard antenna with a wire. Furthermore, the Si24R1 has different power amplifier options as noted in the RF_PWR section (bits 0 through 2) of the RF_SETUP register (address 0x06) of the datasheet. While the options’ values differ from those identified by this library’s API, the underlying commands to configure those options are almost identical to the nRF24L01. Other known clones include the bk242x (also known as RFM7x).

Contributing

Contributions are welcome! Please read our Code of Conduct before contributing to help this project stay welcoming. To contribute, all you need to do is fork this repository, develop your idea(s) and submit a pull request when stable. To initiate a discussion of idea(s), you need only open an issue on the aforementioned repository (doesn’t have to be a bug report).

Future Project Ideas/Additions

The following are only ideas; they are not currently supported by this circuitpython library.

Sphinx documentation

Sphinx is used to build the documentation based on rST files and comments in the code. First, install dependencies (feel free to reuse the virtual environment from above):

python3 -m venv .env
source .env/bin/activate
pip install Sphinx sphinx-rtd-theme

Now, once you have the virtual environment activated:

cd docs
sphinx-build -E -W -b html . _build

This will output the documentation to docs/_build. Open the index.html in your browser to view them. It will also (due to -W) error out on any warning like the Github action, Build CI, does. This is a good way to locally verify it will pass.

nRF24L01 Features

Simple test

Ensure your device works with this simple test.

examples/nrf24l01_simple_test.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
"""
Simple example of using the RF24 class.
"""
import time
import struct
import board
import digitalio as dio
# if running this on a ATSAMD21 M0 based board
# from circuitpython_nrf24l01.rf24_lite import RF24
from circuitpython_nrf24l01.rf24 import RF24

# addresses needs to be in a buffer protocol object (bytearray)
address = b"1Node"

# change these (digital output) pins accordingly
ce = dio.DigitalInOut(board.D4)
csn = dio.DigitalInOut(board.D5)

# using board.SPI() automatically selects the MCU's
# available SPI pins, board.SCK, board.MOSI, board.MISO
spi = board.SPI()  # init spi bus object

# we'll be using the dynamic payload size feature (enabled by default)
# initialize the nRF24L01 on the spi bus object
nrf = RF24(spi, csn, ce)

# set the Power Amplifier level to -12 dBm since this test example is
# usually run with nRF24L01 transceivers in close proximity
nrf.pa_level = -12


def master(count=5):  # count = 5 will only transmit 5 packets
    """Transmits an incrementing integer every second"""
    # set address of RX node into a TX pipe
    nrf.open_tx_pipe(address)
    # ensures the nRF24L01 is in TX mode
    nrf.listen = False

    while count:
        # use struct.pack to packetize your data
        # into a usable payload
        buffer = struct.pack("<i", count)
        # 'i' means a single 4 byte int value.
        # '<' means little endian byte order. this may be optional
        print("Sending: {} as struct: {}".format(count, buffer))
        now = time.monotonic() * 1000  # start timer
        result = nrf.send(buffer)
        if not result:
            print("send() failed or timed out")
        else:
            print("send() successful")
        # print timer results despite transmission success
        print("Transmission took", time.monotonic() * 1000 - now, "ms")
        time.sleep(1)
        count -= 1


def slave(count=5):
    """Polls the radio and prints the received value. This method expires
    after 6 seconds of no received transmission"""
    # set address of TX node into an RX pipe. NOTE you MUST specify
    # which pipe number to use for RX, we'll be using pipe 0
    # pipe number options range [0,5]
    # the pipe numbers used during a transition don't have to match
    nrf.open_rx_pipe(0, address)
    nrf.listen = True  # put radio into RX mode and power up

    start = time.monotonic()
    while count and (time.monotonic() - start) < 6:
        if nrf.any():
            # print details about the received packet (if any)
            print("Found {} bytes on pipe {}".format(nrf.any(), nrf.pipe))
            # retreive the received packet's payload
            rx = nrf.recv()  # clears flags & empties RX FIFO
            # expecting an int, thus the string format '<i'
            buffer = struct.unpack("<i", rx[:4])
            # print the only item in the resulting tuple from
            # using `struct.unpack()`
            print("Received: {}, Raw: {}".format(buffer[0], repr(rx)))
            start = time.monotonic()
            count -= 1
            # this will listen indefinitely till count == 0
        time.sleep(0.25)

    # recommended behavior is to keep in TX mode while idle
    nrf.listen = False  # put the nRF24L01 is in TX mode


print(
    """\
    nRF24L01 Simple test.\n\
    Run slave() on receiver\n\
    Run master() on transmitter"""
)

ACK Payloads Example

This is a test to show how to use custom acknowledgment payloads. See also documentation on ack and load_ack().

examples/nrf24l01_ack_payload_test.py
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
"""
Simple example of using the library to transmit
and retrieve custom automatic acknowledgment payloads.
"""
import time
import board
import digitalio as dio
# if running this on a ATSAMD21 M0 based board
# from circuitpython_nrf24l01.rf24_lite import RF24
from circuitpython_nrf24l01.rf24 import RF24

# change these (digital output) pins accordingly
ce = dio.DigitalInOut(board.D4)
csn = dio.DigitalInOut(board.D5)

# using board.SPI() automatically selects the MCU's
# available SPI pins, board.SCK, board.MOSI, board.MISO
spi = board.SPI()  # init spi bus object

# we'll be using the dynamic payload size feature (enabled by default)
# the custom ACK payload feature is disabled by default
# the custom ACK payload feature should not be enabled
# during instantiation due to its singular use nature
# meaning 1 ACK payload per 1 RX'd payload
nrf = RF24(spi, csn, ce)

# NOTE the the custom ACK payload feature will be enabled
# automatically when you call load_ack() passing:
# a buffer protocol object (bytearray) of
# length ranging [1,32]. And pipe number always needs
# to be an int ranging [0,5]

# to enable the custom ACK payload feature
nrf.ack = True  # False disables again

# set the Power Amplifier level to -12 dBm since this test example is
# usually run with nRF24L01 transceivers in close proximity
nrf.pa_level = -12

# addresses needs to be in a buffer protocol object (bytearray)
address = b"1Node"

# NOTE ACK payloads (like regular payloads and addresses)
# need to be in a buffer protocol object (bytearray)
ACK = b"World "


def master(count=5):  # count = 5 will only transmit 5 packets
    """Transmits a dummy payload every second and prints the ACK payload"""
    # recommended behavior is to keep in TX mode while idle
    nrf.listen = False  # put radio in TX mode

    # set address of RX node into a TX pipe
    nrf.open_tx_pipe(address)

    while count:
        buffer = b"Hello " + bytes([count + 48])  # output buffer
        print("Sending (raw): {}".format(repr(buffer)))
        # to read the ACK payload during TX mode we
        # pass the parameter read_ack as True.
        nrf.ack = True  # enable feature before send()
        now = time.monotonic() * 1000  # start timer
        result = nrf.send(buffer)  # becomes the response buffer
        if not result:
            print("send() failed or timed out")
        else:
            # print the received ACK that was automatically
            # fetched and saved to "buffer" via send()
            print("raw ACK: {}".format(repr(result)))
            # the ACK payload should now be in buffer
        # print timer results despite transmission success
        print("Transmission took", time.monotonic() * 1000 - now, "ms")
        time.sleep(1)
        count -= 1


def slave(count=5):
    """Prints the received value and sends a dummy ACK payload"""
    # set address of TX node into an RX pipe. NOTE you MUST specify
    # which pipe number to use for RX, we'll be using pipe 0
    nrf.open_rx_pipe(0, address)

    # put radio into RX mode, power it up, and set the first
    # transmission's ACK payload and pipe number
    nrf.listen = True
    buffer = ACK + bytes([count + 48])
    # we must set the ACK payload data and corresponding
    # pipe number [0,5]
    nrf.load_ack(buffer, 0)  # load ACK for first response

    start = time.monotonic()
    while count and (time.monotonic() - start) < (count * 2):
        if nrf.any():
            # this will listen indefinitely till count == 0
            count -= 1
            # print details about the received packet (if any)
            print("Found {} bytes on pipe {}".format(nrf.any(), nrf.pipe))
            # retreive the received packet's payload
            rx = nrf.recv()  # clears flags & empties RX FIFO
            print("Received (raw): {}".format(repr(rx)))
            start = time.monotonic()
            if count:  # Going again?
                # build new ACK
                buffer = ACK + bytes([count + 48])
                # load ACK for next response
                nrf.load_ack(buffer, 0)

    # recommended behavior is to keep in TX mode while idle
    nrf.listen = False  # put radio in TX mode
    nrf.flush_tx()  # flush any ACK payload


print(
    """\
    nRF24L01 ACK test\n\
    Run slave() on receiver\n\
    Run master() on transmitter"""
)

Multiceiver Example

This example shows how use a group of 6 nRF24L01 transceivers to transmit to 1 nRF24L01 transceiver. This technique is called “Multiceiver” in the nRF24L01 Specifications Sheet

Note

This example follows the diagram illistrated in figure 12 of section 7.7 of the nRF24L01 Specifications Sheet Please note that if auto_ack (on the base station) and arc (on the trnasmitting nodes) are disabled, then figure 10 of section 7.7 of the nRF24L01 Specifications Sheet would be a better illustration.

Hint

A paraphrased note from the the nRF24L01 Specifications Sheet:

Only when a data pipe receives a complete packet can other data pipes begin to receive data. When multiple [nRF24L01]s are transmitting to [one nRF24L01], the ard can be used to skew the auto retransmission so that they only block each other once.

This basically means that it might help packets get received if the ard attribute is set to various values among multiple transmitting nRF24L01 transceivers.

examples/nrf24l01_multiceiver_test.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
"""
Simple example of using 1 nRF24L01 to receive data from up to 6 other
transceivers. This technique is called "multiceiver" in the datasheet.
For fun, this example also sends an ACK payload from the base station
to the node-1 transmitter.
"""
import time
import board
import digitalio as dio

# if running this on a ATSAMD21 M0 based board
# from circuitpython_nrf24l01.rf24_lite import RF24
from circuitpython_nrf24l01.rf24 import RF24

# change these (digital output) pins accordingly
ce = dio.DigitalInOut(board.D4)
csn = dio.DigitalInOut(board.D5)

# using board.SPI() automatically selects the MCU's
# available SPI pins, board.SCK, board.MOSI, board.MISO
spi = board.SPI()  # init spi bus object

# we'll be using the dynamic payload size feature (enabled by default)
# initialize the nRF24L01 on the spi bus object
nrf = RF24(spi, csn, ce)

# set the Power Amplifier level to -12 dBm since this test example is
# usually run with nRF24L01 transceivers in close proximity
nrf.pa_level = -12

# setup the addresses for all transmitting nRF24L01 nodes
addresses = [
    b"\x78" * 5,
    b"\xF1\xB3\xB4\xB5\xB6",
    b"\xCD\xB3\xB4\xB5\xB6",
    b"\xA3\xB3\xB4\xB5\xB6",
    b"\x0F\xB3\xB4\xB5\xB6",
    b"\x05\xB3\xB4\xB5\xB6"
]

# to use custom ACK payloads, we must enable that feature
nrf.ack = True
# let this be the ACk payload
ACK = b"Yak Back ACK"


def base(timeout=10):
    """Use the nRF24L01 as a base station for lisening to all nodes"""
    # write the addresses to all pipes.
    for pipe_n, addr in enumerate(addresses):
        nrf.open_rx_pipe(pipe_n, addr)
    while nrf.fifo(True, False):  # fill TX FIFO with ACK payloads
        nrf.load_ack(ACK, 1)  # only send ACK payload to node 1
    nrf.listen = True  # put base station into RX mode
    start_timer = time.monotonic()  # start timer
    while time.monotonic() - start_timer < timeout:
        while not nrf.fifo(False, True):  # keep RX FIFO empty for reception
            # show the pipe number that received the payload
            print("node", nrf.pipe, "sent:", nrf.recv())
            start_timer = time.monotonic()  # reset timer with every payload
            if nrf.load_ack(ACK, 1):  # keep TX FIFO full with ACK payloads
                print("\t ACK re-loaded")
    nrf.listen = False


def node(node_number, count=6):
    """start transmitting to the base station.

        :param int node_number: the node's identifying index (from the
            the `addresses` list)
        :param int count: the number of times that the node will transmit
            to the base station.
    """
    nrf.listen = False
    # set the TX address to the address of the base station.
    nrf.open_tx_pipe(addresses[node_number])
    counter = 0
    # use the node_number to identify where the payload came from
    node_id = b"PTX-" + bytes([node_number + 48])
    while counter < count:
        counter += 1
        # payloads will include the node_number and a payload ID character
        payload = node_id + b" payload-ID: " + bytes([node_number + 48])
        payload += bytes([counter + (65 if 0 <= counter < 26 else 71)])
        # show something to see it isn't frozen
        print("attempt {} returned {}".format(counter, nrf.send(payload)))
        time.sleep(0.5)  # slow down the test for readability


print(
    """\
    nRF24L01 Multiceiver test.\n\
    Run base() on the receiver\n\
        base() sends ACK payloads to node 1\n\
    Run node(node_number) on a transmitter\n\
        node()'s parameter, `node_number`, must be in range [0, 5]"""
)

IRQ Pin Example

This is a test to show how to use nRF24L01’s interrupt pin. Be aware that send() clears all IRQ events on exit, so we use the non-blocking write() instead. Also the ack attribute is enabled to trigger the irq_dr event when the master node receives ACK payloads. Simply put, this example is the most advanced example script (in this library), and it runs VERY quickly.

examples/nrf24l01_interrupt_test.py
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
"""
Simple example of detecting (and verifying) the IRQ (interrupt) pin on the
nRF24L01
    .. note:: this script uses the non-blocking `write()` function because
        the function `send()` clears the IRQ flags upon returning
"""
import time
import board
import digitalio as dio
# if running this on a ATSAMD21 M0 based board
# from circuitpython_nrf24l01.rf24_lite import RF24
from circuitpython_nrf24l01.rf24 import RF24

# address needs to be in a buffer protocol object (bytearray is preferred)
address = b"1Node"

# select your digital input pin that's connected to the IRQ pin on the nRF4L01
irq_pin = dio.DigitalInOut(board.D12)
irq_pin.switch_to_input()  # make sure its an input object
# change these (digital output) pins accordingly
ce = dio.DigitalInOut(board.D4)
csn = dio.DigitalInOut(board.D5)

# using board.SPI() automatically selects the MCU's
# available SPI pins, board.SCK, board.MOSI, board.MISO
spi = board.SPI()  # init spi bus object

# we'll be using the dynamic payload size feature (enabled by default)
# initialize the nRF24L01 on the spi bus object
nrf = RF24(spi, csn, ce)

# this example uses the ACK payload to trigger the IRQ pin active for
# the "on data received" event
nrf.ack = True  # enable ACK payloads

# set the Power Amplifier level to -12 dBm since this test example is
# usually run with nRF24L01 transceivers in close proximity
nrf.pa_level = -12


def _ping_and_prompt():
    """transmit 1 payload, wait till irq_pin goes active, print IRQ status
    flags."""
    ce.value = 1  # tell the nRF24L01 to prepare sending a single packet
    time.sleep(0.00001)  # mandatory 10 microsecond pulse starts transmission
    ce.value = 0  # end 10 us pulse; use only 1 buffer from TX FIFO
    while irq_pin.value:  # IRQ pin is active when LOW
        pass
    print("IRQ pin went active LOW.")
    nrf.update()  # update irq_d? status flags
    print(
        "\tirq_ds: {}, irq_dr: {}, irq_df: {}".format(
            nrf.irq_ds, nrf.irq_dr, nrf.irq_df
        )
    )

def master():
    """Transmits 3 times: successfully receive ACK payload first, successfully
    transmit on second, and intentionally fail transmit on the third"""
    # set address of RX node into a TX pipe
    nrf.open_tx_pipe(address)
    # ensures the nRF24L01 is in TX mode
    nrf.listen = False
    # NOTE nrf.power is automatically set to True on first call to nrf.write()
    # NOTE nrf.write() internally calls nrf.clear_status_flags() first

    # load 2 buffers into the TX FIFO; write_only=True leaves CE pin LOW
    nrf.write(b"Ping ", write_only=True)
    nrf.write(b"Pong ", write_only=True)

    # on data ready test
    print("\nConfiguring IRQ pin to only ignore 'on data sent' event")
    nrf.interrupt_config(data_sent=False)
    print("    Pinging slave node for an ACK payload...", end=" ")
    _ping_and_prompt()  # CE pin is managed by this function
    if nrf.irq_dr:
        print("\t'on data ready' event test successful")
    else:
        print("\t'on data ready' event test unsucessful")

    # on data sent test
    print("\nConfiguring IRQ pin to only ignore 'on data ready' event")
    nrf.interrupt_config(data_recv=False)
    print("    Pinging slave node again...             ", end=" ")
    _ping_and_prompt()  # CE pin is managed by this function
    if nrf.irq_ds:
        print("\t'on data sent' event test successful")
    else:
        print("\t'on data sent' event test unsucessful")

    # trigger slave node to exit by filling the slave node's RX FIFO
    print("\nSending one extra payload to fill RX FIFO on slave node.")
    if nrf.send(b"Radio", send_only=True):
        # when send_only parameter is True, send() ignores RX FIFO usage
        print("Slave node should not be listening anymore.")
    else:
        print("Slave node was unresponsive.")

    # on data fail test
    print("\nConfiguring IRQ pin to go active for all events.")
    nrf.interrupt_config()
    print("    Sending a ping to inactive slave node...", end=" ")
    nrf.flush_tx()  # just in case any previous tests failed
    nrf.write(b"Dummy", write_only=True)  # CE pin is left LOW
    _ping_and_prompt()  # CE pin is managed by this function
    if nrf.irq_df:
        print("\t'on data failed' event test successful")
    else:
        print("\t'on data failed' event test unsucessful")
    nrf.flush_tx()  # flush artifact payload in TX FIFO from last test
    # all 3 ACK payloads received were 4 bytes each, and RX FIFO is full
    # so, fetching 12 bytes from the RX FIFO also flushes RX FIFO
    print("\nComplete RX FIFO:", nrf.recv(12))


def slave(timeout=6):  # will listen for 6 seconds before timing out
    """Only listen for 3 payload from the master node"""
    # setup radio to recieve pings, fill TX FIFO with ACK payloads
    nrf.open_rx_pipe(0, address)
    nrf.load_ack(b"Yak ", 0)
    nrf.load_ack(b"Back", 0)
    nrf.load_ack(b" ACK", 0)
    nrf.listen = True  # start listening & clear irq_dr flag
    start_timer = time.monotonic()  # start timer now
    while not nrf.fifo(0, 0) and time.monotonic() - start_timer < timeout:
        # if RX FIFO is not full and timeout is not reached, then keep going
        pass
    nrf.listen = False  # put nRF24L01 in Standby-I mode when idling
    if not nrf.fifo(False, True):  # if RX FIFO is not empty
        # all 3 payloads received were 5 bytes each, and RX FIFO is full
        # so, fetching 15 bytes from the RX FIFO also flushes RX FIFO
        print("Complete RX FIFO:", nrf.recv(15))
    nrf.flush_tx()  # discard any pending ACK payloads


print(
    """\
    nRF24L01 Interrupt pin test.\n\
    Make sure the IRQ pin is connected to the MCU\n\
    Run slave() on receiver\n\
    Run master() on transmitter"""
)

Library-Specific Features

Stream Example

This is a test to show how to use the send() to transmit multiple payloads with 1 function call.

examples/nrf24l01_stream_test.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
"""
Example of library usage for streaming multiple payloads.
"""
import time
import board
import digitalio as dio
# if running this on a ATSAMD21 M0 based board
# from circuitpython_nrf24l01.rf24_lite import RF24
from circuitpython_nrf24l01.rf24 import RF24

# addresses needs to be in a buffer protocol object (bytearray)
address = b"1Node"

# change these (digital output) pins accordingly
ce = dio.DigitalInOut(board.D4)
csn = dio.DigitalInOut(board.D5)

# using board.SPI() automatically selects the MCU's
# available SPI pins, board.SCK, board.MOSI, board.MISO
spi = board.SPI()  # init spi bus object

# we'll be using the dynamic payload size feature (enabled by default)
# initialize the nRF24L01 on the spi bus object
nrf = RF24(spi, csn, ce)

# set the Power Amplifier level to -12 dBm since this test example is
# usually run with nRF24L01 transceivers in close proximity
nrf.pa_level = -12


def master(count=1):  # count = 5 will transmit the list 5 times
    """Transmits a massive buffer of payloads"""
    # lets create a `list` of payloads to be streamed to
    # the nRF24L01 running slave()
    buffers = []
    # we'll use SIZE for the number of payloads in the list and the
    # payloads' length
    size = 32
    for i in range(size):
        # prefix payload with a sequential letter to indicate which
        # payloads were lost (if any)
        buff = bytes([i + (65 if 0 <= i < 26 else 71)])
        for j in range(size - 1):
            char = bool(j >= (size - 1) / 2 + abs((size - 1) / 2 - i))
            char |= bool(j < (size - 1) / 2 - abs((size - 1) / 2 - i))
            buff += bytes([char + 48])
        buffers.append(buff)
        del buff

    # set address of RX node into a TX pipe
    nrf.open_tx_pipe(address)
    # ensures the nRF24L01 is in TX mode
    nrf.listen = False

    successful = 0
    for _ in range(count):
        now = time.monotonic() * 1000  # start timer
        result = nrf.send(buffers, force_retry=2)
        print("Transmission took", time.monotonic() * 1000 - now, "ms")
        for r in result:
            successful += 1 if r else 0
    print(
        "successfully sent {}% ({}/{})".format(
            successful / (size* count) * 100, successful, size * count
        )
    )


def slave(timeout=5):
    """Stops listening after timeout with no response"""
    # set address of TX node into an RX pipe. NOTE you MUST specify
    # which pipe number to use for RX, we'll be using pipe 0
    # pipe number options range [0,5]
    # the pipe numbers used during a transition don't have to match
    nrf.open_rx_pipe(0, address)
    nrf.listen = True  # put radio into RX mode and power up

    count = 0
    now = time.monotonic()  # start timer
    while time.monotonic() < now + timeout:
        if nrf.any():
            count += 1
            # retreive the received packet's payload
            rx = nrf.recv()  # clears flags & empties RX FIFO
            print("Received: {} - {}".format(repr(rx), count))
            now = time.monotonic()

    # recommended behavior is to keep in TX mode while idle
    nrf.listen = False  # put the nRF24L01 is in TX mode


print(
    """\
    nRF24L01 Stream test\n\
    Run slave() on receiver\n\
    Run master() on transmitter"""
)

Context Example

This is a test to show how to use The with statement blocks to manage multiple different nRF24L01 configurations on 1 transceiver.

examples/nrf24l01_context_test.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
"""
Simple example of library usage in context.
This will not transmit anything, but rather
display settings after changing contexts ( & thus configurations)

    .. warning:: This script is not compatible with the rf24_lite module
"""
import board
import digitalio as dio
from circuitpython_nrf24l01.rf24 import RF24
from circuitpython_nrf24l01.fake_ble import FakeBLE

# change these (digital output) pins accordingly
ce = dio.DigitalInOut(board.D4)
csn = dio.DigitalInOut(board.D5)

# using board.SPI() automatically selects the MCU's
# available SPI pins, board.SCK, board.MOSI, board.MISO
spi = board.SPI()  # init spi bus object

# initialize the nRF24L01 objects on the spi bus object
# the first object will have all the features enabled
nrf = RF24(spi, csn, ce)
# enable the option to use custom ACK payloads
nrf.ack = True
# set the static payload length to 8 bytes
nrf.payload_length = 8
# RF power amplifier is set to -18 dbm
nrf.pa_level = -18

# the second object has most features disabled/altered
ble = FakeBLE(spi, csn, ce)
# the IRQ pin is configured to only go active on "data fail"
# NOTE BLE operations prevent the IRQ pin going active on "data fail" events
ble.interrupt_config(data_recv=False, data_sent=False)
# using a channel 2
ble.channel = 2
# RF power amplifier is set to -12 dbm
ble.pa_level = -12

print("\nsettings configured by the nrf object")
with nrf:
    # only the first character gets written because it is on a pipe_number > 1
    nrf.open_rx_pipe(5, b"1Node")  # NOTE we do this inside the "with" block

    # display current settings of the nrf object
    nrf.what_happened(True)  # True dumps pipe info

print("\nsettings configured by the ble object")
with ble as nerf:  # the "as nerf" part is optional
    nerf.what_happened(1)

# if you examine the outputs from what_happened() you'll see:
#   pipe 5 is opened using the nrf object, but closed using the ble object.
#   pipe 0 is closed using the nrf object, but opened using the ble object.
#   also notice the different addresses bound to the RX pipes
# this is because the "with" statements load the existing settings
# for the RF24 object specified after the word "with".

# NOTE it is not advised to manipulate seperate RF24 objects outside of the
# "with" block; you will encounter bugs about configurations when doing so.
# Be sure to use 1 "with" block per RF24 object when instantiating multiple
# RF24 objects in your program.
# NOTE exiting a "with" block will always power down the nRF24L01
# NOTE upon instantiation, this library closes all RX pipes &
# extracts the TX/RX addresses from the nRF24L01 registers

OTA compatibility

Fake BLE Example

This is a test to show how to use the nRF24L01 as a BLE advertising beacon using the FakeBLE class.

examples/nrf24l01_fake_ble_test.py
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
"""
This example uses the nRF24L01 as a 'fake' BLE Beacon

    .. warning:: ATSAMD21 M0-based boards have memory allocation
        error when loading 'fake_ble.mpy'
"""
import time
import board
import digitalio as dio
from circuitpython_nrf24l01.fake_ble import (
    chunk,
    FakeBLE,
    UrlServiceData,
    BatteryServiceData,
    TemperatureServiceData,
)

# change these (digital output) pins accordingly
ce = dio.DigitalInOut(board.D4)
csn = dio.DigitalInOut(board.D5)

# using board.SPI() automatically selects the MCU's
# available SPI pins, board.SCK, board.MOSI, board.MISO
spi = board.SPI()  # init spi bus object

# initialize the nRF24L01 on the spi bus object as a BLE compliant radio
nrf = FakeBLE(spi, csn, ce)

# the name parameter is going to be its broadcasted BLE name
# this can be changed at any time using the `name` attribute
# nrf.name = b"foobar"

# you can optionally set the arbitrary MAC address to be used as the
# BLE device's MAC address. Otherwise this is randomly generated upon
# instantiation of the FakeBLE object.
# nrf.mac = b"\x19\x12\x14\x26\x09\xE0"

# set the Power Amplifier level to -12 dBm since this test example is
# usually run with nRF24L01 transceiver in close proximity to the
# BLE scanning application
nrf.pa_level = -12


def _prompt(count, iterator):
    if (count - iterator) % 5 == 0 or (count - iterator) < 5:
        if count - iterator - 1:
            print(count - iterator, "advertisments left to go!")
        else:
            print(count - iterator, "advertisment left to go!")


# create an object for manipulating the battery level data
battery_service = BatteryServiceData()
# battery level data is 1 unsigned byte representing a percentage
battery_service.data = 85


def master(count=50):
    """Sends out the device information twice a second."""
    # using the "with" statement is highly recommended if the nRF24L01 is
    # to be used for more than a BLE configuration
    with nrf as ble:
        ble.name = b"nRF24L01"
        # include the radio's pa_level attribute in the payload
        ble.show_pa_level = True
        print(
            "available bytes in next payload:",
            ble.available(chunk(battery_service.buffer))
        )  # using chunk() gives an accurate estimate of available bytes
        for i in range(count):  # advertise data this many times
            if ble.available(chunk(battery_service.buffer)) >= 0:
                _prompt(count, i)  # something to show that it isn't frozen
                # broadcast the device name, MAC address, &
                # battery charge info; 0x16 means service data
                ble.advertise(battery_service.buffer, data_type=0x16)
                # channel hoping is recommended per BLE specs
                ble.hop_channel()
                time.sleep(0.5)  # wait till next broadcast
    # nrf.show_pa_level & nrf.name both are set to false when
    # exiting a with statement block


# create an object for manipulating temperature measurements
temperature_service = TemperatureServiceData()
# temperature's float data has up to 2 decimal places of percision
temperature_service.data = 42.0


def send_temp(count=50):
    """Sends out a fake temperature twice a second."""
    with nrf as ble:
        ble.name = b"nRF24L01"
        print(
            "available bytes in next payload:",
            ble.available(chunk(temperature_service.buffer))
        )
        for i in range(count):
            if ble.available(chunk(temperature_service.buffer)) >= 0:
                _prompt(count, i)
                # broadcast a temperature measurement; 0x16 means service data
                ble.advertise(temperature_service.buffer, data_type=0x16)
                ble.hop_channel()
                time.sleep(0.2)


# use the Eddystone protocol from Google to broadcast a URL as
# service data. We'll need an object to manipulate that also
url_service = UrlServiceData()
# the data attribute converts a URL string into a simplified
# bytes object using byte codes defined by the Eddystone protocol.
url_service.data = "http://www.google.com"
# Eddystone protocol requires an estimated TX PA level at 1 meter
# lower this estimate since we lowered the actual `ble.pa_level`
url_service.pa_level_at_1_meter = -45  # defaults to -25 dBm

def send_url(count=50):
    """Sends out a URL twice a second."""
    with nrf as ble:
        print(
            "available bytes in next payload:",
            ble.available(chunk(url_service.buffer))
        )
        # NOTE we did NOT set a device name in this with block
        for i in range(count):
            # URLs easily exceed the nRF24L01's max payload length
            if ble.available(chunk(url_service.buffer)) >= 0:
                _prompt(count, i)
                ble.advertise(url_service.buffer, 0x16)
                ble.hop_channel()
                time.sleep(0.2)

print(
    """\
    nRF24L01 fake BLE beacon test.\n\
    Run master() to broadcast the device name, pa_level, & battery charge\n\
    Run send_temp() to broadcast the device name & a temperature\n\
    Run send_url() to broadcast a custom URL link"""
)

TMRh20’s Arduino library

This test is meant to prove compatibility with the popular Arduino library for the nRF24L01 by TMRh20 (available for install via the Arduino IDE’s Library Manager). The following code has been designed/test with the TMRh20 library example named GettingStarted_HandlingData.ino. If you changed the role variable in the TMRh20 sketch, you will have to adjust the addresses assigned to the pipes in this script.

examples/nrf24l01_2arduino_handling_data.py
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
"""
Example of library driving the nRF24L01 to communicate with a nRF24L01 driven by
the TMRh20 Arduino library. The Arduino program/sketch that this example was
designed for is named GettingStarted_HandlingData.ino and can be found in the "RF24"
examples after the TMRh20 library is installed from the Arduino Library Manager.
"""
import time
import struct
import board
import digitalio as dio
# if running this on a ATSAMD21 M0 based board
# from circuitpython_nrf24l01.rf24_lite import RF24
from circuitpython_nrf24l01.rf24 import RF24

# addresses needs to be in a buffer protocol object (bytearray)
address = [b"1Node", b"2Node"]

# change these (digital output) pins accordingly
ce = dio.DigitalInOut(board.D4)
csn = dio.DigitalInOut(board.D5)

# using board.SPI() automatically selects the MCU's
# available SPI pins, board.SCK, board.MOSI, board.MISO
spi = board.SPI()  # init spi bus object

# initialize the nRF24L01 on the spi bus object
nrf = RF24(spi, csn, ce)
nrf.dynamic_payloads = False  # the default in the TMRh20 arduino library

# set the Power Amplifier level to -12 dBm since this test example is
# usually run with nRF24L01 transceivers in close proximity
nrf.pa_level = -12

# set address of TX node into a RX pipe
nrf.open_rx_pipe(1, address[1])
# set address of RX node into a TX pipe
nrf.open_tx_pipe(address[0])

# pylint: disable=too-few-public-methods
class DataStruct:
    """A data structure to hold transmitted values as the
    'HandlingData' part of the TMRh20 library example"""
    time = 0  # in milliseconds (used as start of timer)
    value = 1.22  # incremented  by 0.01 with every transmission
# pylint: enable=too-few-public-methods

myData = DataStruct()


def master(count=5):  # count = 5 will only transmit 5 packets
    """Transmits an arbitrary unsigned long value every second"""
    while count:
        nrf.listen = False  # ensures the nRF24L01 is in TX mode
        print("Now Sending")
        myData.time = int(time.monotonic() * 1000)  # start timer
        # use struct.pack to packetize your data into a usable payload
        # '<' means little endian byte order.
        # 'L' means a single 4 byte unsigned long value.
        # 'f' means a single 4 byte float value.
        buffer = struct.pack("<Lf", myData.time, myData.value)
        result = nrf.send(buffer)
        if not result:
            print("send() failed or timed out")
        else:
            nrf.listen = True  # get radio ready to receive a response
            timeout = True  # used to determine if response timed out
            while time.monotonic() * 1000 - myData.time < 200:
                # the arbitrary 200 ms timeout value is also used in the
                # TMRh20 library's GettingStarted_HandlingData sketch
                if nrf.any():
                    end_timer = time.monotonic() * 1000  # end timer
                    rx = nrf.recv()
                    rx = struct.unpack("<Lf", rx[:8])
                    myData.value = rx[1]  # save the new float value
                    timeout = False  # skips timeout prompt
                    # print total time to send and receive data
                    print(
                        "Sent {} Got Response: {}".format(
                            struct.unpack("<Lf", buffer),
                            rx
                        )
                    )
                    print("Round-trip delay:", end_timer - myData.time, "ms")
                    break
            if timeout:
                print("failed to get a response; timed out")
        count -= 1
        time.sleep(1)


def slave(count=3):
    """Polls the radio and prints the received value. This method expires
    after 6 seconds of no received transmission"""
    myData.time = time.monotonic() * 1000  # in milliseconds
    while count and (time.monotonic() * 1000 - myData.time) < 6000:
        nrf.listen = True  # put radio into RX mode and power up
        if nrf.any():
            # retreive the received packet's payload
            buffer = nrf.recv()  # clears flags & empties RX FIFO
            # increment floating value as part of the "HandlingData" test
            myData.value = struct.unpack("<f", buffer[4:8])[0] + 0.01
            nrf.listen = False  # ensures the nRF24L01 is in TX mode
            myData.time = time.monotonic() * 1000
            # echo buffer[:4] appended with incremented float
            result = nrf.send(buffer[:4] + struct.pack("<f", myData.value))
            end_timer = time.monotonic() * 1000  # in milliseconds
            # expecting an unsigned long & a float, thus the
            # string format "<Lf"; buffer[:8] ignores the padded 0s
            rx = struct.unpack("<Lf", buffer[:8])
            # print the unsigned long and float data sent in the response
            print("Responding: {}, {}".format(rx[0], rx[1] + 0.01))
            if not result:
                print("response failed or timed out")
            else:
                # print timer results on transmission success
                print(
                    "successful response took {} ms".format(
                        end_timer - myData.time
                    )
                )
            # this will listen indefinitely till counter == 0
            count -= 1
    # recommended behavior is to keep in TX mode when in idle
    nrf.listen = False  # put the nRF24L01 in TX mode + Standby-I power state


print(
    """\
    nRF24L01 communicating with an Arduino running the\n\
    TMRh20 library's "GettingStarted_HandlingData.ino" example.\n\
    Run slave() on receiver\n\
    Run master() on transmitter"""
)

Troubleshooting info

Important

The nRF24L01 has 3 key features that can be interdependent of each other. Their priority of dependence is as follows:

  1. auto_ack feature provides transmission verification by using the RX nRF24L01 to automatically and imediatedly send an acknowledgment (ACK) packet in response to received payloads. auto_ack does not require dynamic_payloads to be enabled.
  2. dynamic_payloads feature allows either TX/RX nRF24L01 to be able to send/receive payloads with their size written into the payloads’ packet. With this disabled, both RX/TX nRF24L01 must use matching payload_length attributes. For dynamic_payloads to be enabled, the auto_ack feature must be enabled. Although, the auto_ack feature can be used when the dynamic_payloads feature is disabled.
  3. ack feature allows the MCU to append a payload to the ACK packet, thus instant bi-directional communication. A transmitting ACK payload must be loaded into the nRF24L01’s TX FIFO buffer (done using load_ack()) BEFORE receiving the payload that is to be acknowledged. Once transmitted, the payload is released from the TX FIFO buffer. This feature requires the auto_ack and dynamic_payloads features enabled.

Remeber that the nRF24L01’s FIFO (first-in,first-out) buffer has 3 levels. This means that there can be up to 3 payloads waiting to be read (RX) and up to 3 payloads waiting to be transmit (TX).

With the auto_ack feature enabled, you get:

  • cyclic redundancy checking (crc) automatically enabled
  • to change amount of automatic re-transmit attempts and the delay time between them. See the arc and ard attributes.

Note

A word on pipes vs addresses vs channels.

You should think of the data pipes as a “parking spot” for your payload. There are only six data pipes on the nRF24L01, thus it can simultaneously “listen” to a maximum of 6 other nRF24L01 radios. However, it can only “talk” to 1 other nRF24L01 at a time).

The specified address is not the address of an nRF24L01 radio, rather it is more like a path that connects the endpoints. When assigning addresses to a data pipe, you can use any 5 byte long address you can think of (as long as the first byte is unique among simultaneously broadcasting addresses), so you’re not limited to communicating with only the same 6 nRF24L01 radios.

Finnaly, the radio’s channel is not be confused with the radio’s pipes. Channel selection is a way of specifying a certain radio frequency (frequency = [2400 + channel] MHz). Channel defaults to 76 (like the arduino library), but options range from 0 to 125 – that’s 2.4 GHz to 2.525 GHz. The channel can be tweaked to find a less occupied frequency amongst Bluetooth, WiFi, or other ambient signals that use the same spectrum of frequencies.

Warning

For successful transmissions, most of the endpoint trasceivers’ settings/features must match. These settings/features include:

In fact the only attributes that aren’t required to match on both endpoint transceivers would be the identifying data pipe number (passed to open_rx_pipe() or load_ack()), pa_level, arc, & ard attributes. The ask_no_ack feature can be used despite the settings/features configuration (see send() & write() function parameters for more details).

About the lite version

This library contains a “lite” version of rf24.py titled rf24_lite.py. It has been developed to save space on microcontrollers with limited amount of RAM and/or storage (like boards using the ATSAMD21 M0). The following functionality has been removed from the lite version:

  • The FakeBLE class is not compatible with the rf24_lite.py module.

  • is_plus_variant is removed, meaning the lite version is not compatibility with the older non-plus variants of the nRF24L01.

  • address() removed.

  • what_happened() removed. However you can use the following function to dump all available registers’ values (for advanced users):

    # let `nrf` be the instantiated RF24 object
    def dump_registers(end=0x1e):
        for i in range(end):
            if i in (0xA, 0xB, 0x10):
                print(hex(i), "=", nrf._reg_read_bytes(i))
            elif i not in (0x18, 0x19, 0x1a, 0x1b):
                print(hex(i), "=", hex(nrf._reg_read(i)))
    
  • dynamic_payloads applies to all pipes, not individual pipes.

  • payload_length applies to all pipes, not individual pipes.

  • read_ack() removed. This is deprecated on next major release anyway; use recv() instead.

  • load_ack() is available, but it will not throw exceptions for malformed buf or invalid pipe_number parameters.

  • crc removed. 2-bytes encoding scheme (CRC16) is always enabled.

  • auto_ack removed. This is always enabled for all pipes. Pass ask_no_ack parameter as True to send() or write() to disable automatic acknowledgement for TX operations.

  • is_lna_enabled removed as it only affects non-plus variants of the nRF24L01.

  • pa_level is available, but it will not accept a list or tuple.

  • rpd, start_carrier_wave(), & stop_carrier_wave() removed. These only perform a test of the nRF24L01’s hardware.

  • CSN_DELAY removed. This is hard-coded to 5 milliseconds

  • All comments and docstrings removed, meaning help() will not provide any specific information. Exception prompts have also been reduced and adjusted accordingly.

  • Cannot switch between different radio configurations using context manager (the The with statement blocks). It is advised that only one RF24 object be instantiated when RAM is limited (less than or equal to 32KB).

Testing nRF24L01+PA+LNA module

The following are semi-successful test results using a nRF24L01+PA+LNA module:

The Setup

I wrapped the PA/LNA module with electrical tape and then foil around that (for shielding) while being very careful to not let the foil touch any current carrying parts (like the GPIO pins and the soldier joints for the antenna mount). Then I wired up a PA/LNA module with a 3V regulator (L4931 with a 2.2 µF capacitor between Vout & GND) using my ItsyBitsy M4 5V (USB) pin going directly to the L4931 Vin pin. The following are experiences from running simple, ack, & stream examples with a reliable nRF24L01+ (no PA/LNA) on the other end (driven by a Raspberry Pi 2):

Results (ordered by pa_level settings)

  • 0 dBm: master() worked the first time (during simple example) then continuously failed (during all examples). slave() worked on simple & stream examples, but the opposing master() node reporting that ACK packets (without payloads) were not received from the PA/LNA module; slave() failed to send ACK packet payloads during the ack example.
  • -6 dBm: master() worked consistently on simple, ack, & stream example. slave() worked reliably on simple & stream examples, but failed to transmit any ACK packet payloads in the ack example.
  • -12 dBm: master() worked consistently on simple, ack, & stream example. slave() worked reliably on simple & stream examples, but failed to transmit some ACK packet payloads in the ack example.
  • -18 dBm: master() worked consistently on simple, ack, & stream example. slave() worked reliably on simple, ack, & stream examples, meaning all ACK packet payloads were successfully transmit in the ack example.

I should note that without shielding the PA/LNA module and using the L4931 3V regulator, no TX transmissions got sent (including ACK packets for the auto-ack feature).

Conclusion

The PA/LNA modules seem to require quite a bit more power to transmit. The L4931 regulator that I used in the tests boasts a 300 mA current limit and a typical current of 250 mA. While the ItsyBitsy M4 boasts a 500 mA max, it would seem that much of that is consumed internally. Since playing with the pa_level is a current saving hack (as noted in the datasheet), I can only imagine that a higher power 3V regulator may enable sending transmissions (including ACK packets – with or without ACK payloads attached) from PA/LNA modules using higher pa_level settings. More testing is called for, but I don’t have an oscilloscope to measure the peak current draws.

Basic API

Constructor

class circuitpython_nrf24l01.rf24.RF24(spi, csn, ce, spi_frequency=10000000)[source]

A driver class for the nRF24L01(+) transceiver radios.

This class aims to be compatible with other devices in the nRF24xxx product line that implement the Nordic proprietary Enhanced ShockBurst Protocol (and/or the legacy ShockBurst Protocol), but officially only supports (through testing) the nRF24L01 and nRF24L01+ devices.

Parameters:
  • spi (SPI) –

    The object for the SPI bus that the nRF24L01 is connected to.

    Tip

    This object is meant to be shared amongst other driver classes (like adafruit_mcp3xxx.mcp3008 for example) that use the same SPI bus. Otherwise, multiple devices on the same SPI bus with different spi objects may produce errors or undesirable behavior.

  • csn (DigitalInOut) – The digital output pin that is connected to the nRF24L01’s CSN (Chip Select Not) pin. This is required.
  • ce (DigitalInOut) – The digital output pin that is connected to the nRF24L01’s CE (Chip Enable) pin. This is required.
  • spi_frequency (int) – Specify which SPI frequency (in Hz) to use on the SPI bus. This parameter only applies to the instantiated object and is made persistent via SPIDevice.

open_tx_pipe()

RF24.open_tx_pipe(address)[source]

This function is used to open a data pipe for OTA (over the air) TX transmissions.

Parameters:address (bytearray,bytes) – The virtual address of the receiving nRF24L01. The address specified here must match the address set to one of the RX data pipes of the receiving nRF24L01. The existing address can be altered by writing a bytearray with a length less than 5. The nRF24L01 will use the first address_length number of bytes for the RX address on the specified data pipe.

Note

There is no option to specify which data pipe to use because the nRF24L01 only uses data pipe 0 in TX mode. Additionally, the nRF24L01 uses the same data pipe (pipe 0) for receiving acknowledgement (ACK) packets in TX mode when the auto_ack attribute is enabled for data pipe 0. Thus, RX pipe 0 is appropriated with the TX address (specified here) when auto_ack is enabled for data pipe 0.

close_rx_pipe()

RF24.close_rx_pipe(pipe_number)[source]

This function is used to close a specific data pipe from OTA (over the air) RX transmissions.

Parameters:pipe_number (int) – The data pipe to use for RX transactions. This must be in range [0, 5]. Otherwise a IndexError exception is thrown.

open_rx_pipe()

RF24.open_rx_pipe(pipe_number, address)[source]

This function is used to open a specific data pipe for OTA (over the air) RX transmissions.

Parameters:
  • pipe_number (int) – The data pipe to use for RX transactions. This must be in range [0, 5]. Otherwise a IndexError exception is thrown.
  • address (bytearray,bytes) – The virtual address to the receiving nRF24L01. If using a pipe_number greater than 1, then only the MSByte of the address is written, so make sure MSByte (first character) is unique among other simultaneously receiving addresses. The existing address can be altered by writing a bytearray with a length less than 5. The nRF24L01 will use the first address_length number of bytes for the RX address on the specified data pipe.

Note

The nRF24L01 shares the addresses’ last 4 LSBytes on data pipes 2 through 5. These shared LSBytes are determined by the address set to data pipe 1.

listen

RF24.listen

An attribute to represent the nRF24L01 primary role as a radio. Setting this attribute incorporates the proper transitioning to/from RX mode as it involves playing with the power attribute and the nRF24L01’s CE pin. This attribute does not power down the nRF24L01, but will power it up when needed; use power attribute set to False to put the nRF24L01 to sleep.

A valid input value is a bool in which:

  • True enables RX mode. Additionally, per Appendix B of the nRF24L01+ Specifications Sheet, this attribute flushes the RX FIFO, clears the irq_dr status flag, and puts nRF24L01 in power up mode. Notice the CE pin is be held HIGH during RX mode.
  • False disables RX mode. As mentioned in above link, this puts nRF24L01’s power in Standby-I (CE pin is LOW meaning low current & no transmissions) mode which is ideal for post-reception work. Disabing RX mode doesn’t flush the RX/TX FIFO buffers, so remember to flush your 3-level FIFO buffers when appropriate using flush_tx() or flush_rx() (see also the recv() function).

any()

RF24.any()[source]

This function checks if the nRF24L01 has received any data at all, and then reports the next available payload’s length (in bytes).

Returns:
  • int of the size (in bytes) of an available RX payload (if any).
  • 0 if there is no payload in the RX FIFO buffer.

recv()

RF24.recv(length=None)[source]

This function is used to retrieve the next available payload in the RX FIFO buffer, then clears the irq_dr status flag.

This function can also be used to fetch the last ACK packet’s payload if ack is enabled.

Parameters:length (int) –

An optional parameter to specify how many bytes to read from the RX FIFO buffer. This parameter is not constrained in any way.

  • If this parameter is less than the length of the first available payload in the RX FIFO buffer, then the payload will remain in the RX FIFO buffer until the entire payload is fetched by this function.
  • If this parameter is greater than the next available payload’s length, then additional data from other payload(s) in the RX FIFO buffer are returned.

Note

The nRF24L01 will repeatedly return the last byte fetched from the RX FIFO buffer when there is no data to return (even if the RX FIFO is empty). Be aware that a payload is only removed from the RX FIFO buffer when the entire payload has been fetched by this function. Notice that this function always starts reading data from the first byte of the first available payload (if any) in the RX FIFO buffer. Remember the RX FIFO buffer can hold up to 3 payloads at a maximum of 32 bytes each.

Returns:If the length parameter is not specified, then this function returns a bytearray of the RX payload data or None if there is no payload. This also depends on the setting of dynamic_payloads & payload_length attributes. Consider the following two scenarios:
  • If the dynamic_payloads attribute is disabled, then the returned bytearray’s length is equal to the user defined payload_length attribute for the data pipe that received the payload.
  • If the dynamic_payloads attribute is enabled, then the returned bytearray’s length is equal to the payload’s length

When the length parameter is specified, this function strictly returns a bytearray of that length despite the contents of the RX FIFO.

send()

RF24.send(buf, ask_no_ack=False, force_retry=0, send_only=False)[source]

This blocking function is used to transmit payload(s).

Returns:

  • list if a list or tuple of payloads was passed as the buf parameter. Each item in the returned list will contain the returned status for each corresponding payload in the list/tuple that was passed. The return statuses will be in one of the following forms:
  • False if transmission fails. Transmission failure can only be detected if arc is greater than 0.
  • True if transmission succeeds.
  • bytearray or True when the ack attribute is True. Because the payload expects a responding custom ACK payload, the response is returned (upon successful transmission) as a bytearray (or True if ACK payload is empty). Returning the ACK payload can be bypassed by setting the send_only parameter as True.

Parameters:
  • buf (bytearray,bytes,list,tuple) –

    The payload to transmit. This bytearray must have a length in range [1, 32], otherwise a ValueError exception is thrown. This can also be a list or tuple of payloads (bytearray); in which case, all items in the list/tuple are processed for consecutive transmissions.

    • If the dynamic_payloads attribute is disabled for data pipe 0 and this bytearray’s length is less than the payload_length attribute for pipe 0, then this bytearray is padded with zeros until its length is equal to the payload_length attribute for pipe 0.
    • If the dynamic_payloads attribute is disabled for data pipe 0 and this bytearray’s length is greater than payload_length attribute for pipe 0, then this bytearray’s length is truncated to equal the payload_length attribute for pipe 0.
  • ask_no_ack (bool) –

    Pass this parameter as True to tell the nRF24L01 not to wait for an acknowledgment from the receiving nRF24L01. This parameter directly controls a NO_ACK flag in the transmission’s Packet Control Field (9 bits of information about the payload). Therefore, it takes advantage of an nRF24L01 feature specific to individual payloads, and its value is not saved anywhere. You do not need to specify this for every payload if the arc attribute is disabled, however setting this parameter to True will work despite the arc attribute’s setting.

    Note

    Each transmission is in the form of a packet. This packet contains sections of data around and including the payload. See Chapter 7.3 in the nRF24L01 Specifications Sheet for more details.

  • force_retry (int) – The number of brute-force attempts to resend() a failed transmission. Default is 0. This parameter has no affect on transmissions if arc is 0 or if ask_no_ack parameter is set to True. Each re-attempt still takes advantage of arc & ard attributes. During multi-payload processing, this parameter is meant to slow down CircuitPython devices just enough for the Raspberry Pi to catch up (due to the Raspberry Pi’s seemingly slower SPI speeds).
  • send_only (bool) – This parameter only applies when the ack attribute is set to True. Pass this parameter as True if the RX FIFO is not to be manipulated. Many other libraries’ behave as though this parameter is True (e.g. The popular TMRh20 Arduino RF24 library). This parameter defaults to False. Use recv() to get the ACK payload (if there is any) from the RX FIFO.Remember that the RX FIFO can only hold up to 3 payloads at once.

Tip

It is highly recommended that arc attribute is enabled (greater than 0) when sending multiple payloads. Test results with the arc attribute disabled were rather poor (less than 79% received by a Raspberry Pi). This same advice applies to the ask_no_ack parameter (leave it as False for multiple payloads).

Warning

The nRF24L01 will block usage of the TX FIFO buffer upon failed transmissions. Failed transmission’s payloads stay in TX FIFO buffer until the MCU calls flush_tx() and clear_status_flags(). Therefore, this function will discard failed transmissions’ payloads.

Advanced API

what_happened()

RF24.what_happened(dump_pipes=False)[source]

This debuggung function aggregates and outputs all status/condition related information from the nRF24L01.

Some information may be irrelevant depending on nRF24L01’s state/condition.

Prints:
  • Is a plus variant True means the transceiver is a nRF24L01+. False means the transceiver is a nRF24L01 (not a plus variant).
  • Channel The current setting of the channel attribute
  • RF Data Rate The current setting of the RF data_rate attribute.
  • RF Power Amplifier The current setting of the pa_level attribute.
  • CRC bytes The current setting of the crc attribute
  • Address length The current setting of the address_length attribute
  • TX Payload lengths The current setting of the payload_length attribute for TX operations (concerning data pipe 0)
  • Auto retry delay The current setting of the ard attribute
  • Auto retry attempts The current setting of the arc attribute
  • Packets lost on current channel Total amount of packets lost (transmission failures). This only resets when the channel is changed. This count will only go up 15.
  • Retry attempts made for last transmission Amount of attempts to re-transmit during last transmission (resets per payload)
  • IRQ - Data Ready The current setting of the IRQ pin on “Data Ready” event
  • IRQ - Data Sent The current setting of the IRQ pin on “Data Sent” event
  • IRQ - Data Fail The current setting of the IRQ pin on “Data Fail” event
  • Data Ready Is there RX data ready to be read? (state of the irq_dr flag)
  • Data Sent Has the TX data been sent? (state of the irq_ds flag)
  • Data Failed Has the maximum attempts to re-transmit been reached? (state of the irq_df flag)
  • TX FIFO full Is the TX FIFO buffer full? (state of the tx_full flag)
  • TX FIFO empty Is the TX FIFO buffer empty?
  • RX FIFO full Is the RX FIFO buffer full?
  • RX FIFO empty Is the RX FIFO buffer empty?
  • Custom ACK payload Is the nRF24L01 setup to use an extra (user defined) payload attached to the acknowledgment packet? (state of the ack attribute)
  • Ask no ACK Is the nRF24L01 setup to transmit individual packets that don’t require acknowledgment?
  • Automatic Acknowledgment The status of the auto_ack feature. If this value is a binary representation, then each bit represents the feature’s status for each pipe.
  • Dynamic Payloads The status of the dynamic_payloads feature. If this value is a binary representation, then each bit represents the feature’s status for each pipe.
  • Primary Mode The current mode (RX or TX) of communication of the nRF24L01 device.
  • Power Mode The power state can be Off, Standby-I, Standby-II, or On.
Parameters:

dump_pipes (bool) –

True appends the output and prints:

  • the current address used for TX transmissions. This value is the entire content of the nRF24L01’s register about the TX address (despite what address_length is set to).
  • Pipe [#] ([open/closed]) bound: [address] where # represent the pipe number, the open/closed status is relative to the pipe’s RX status, and address is the full value stored in the nRF24L01’s RX address registers (despite what address_length is set to.
  • if the pipe is open, then the output also prints expecting [X] byte static payloads where X is the payload_length (in bytes) the pipe is setup to receive when dynamic_payloads is disabled for that pipe.

This parameter’s default is False and skips this extra information.

is_plus_variant

RF24.is_plus_variant

A bool attribute to descibe if the nRF24L01 is a plus variant or not (read-only). This information is detirmined upon instantiation.

load_ack()

RF24.load_ack(buf, pipe_number)[source]

This allows the MCU to specify a payload to be allocated into the TX FIFO buffer for use on a specific data pipe.

This payload will then be appended to the automatic acknowledgment (ACK) packet that is sent when new data is received on the specified pipe. See recv() on how to fetch a received custom ACK payloads.

Parameters:
  • buf (bytearray,bytes) – This will be the data attached to an automatic ACK packet on the incoming transmission about the specified pipe_number parameter. This must have a length in range [1, 32] bytes, otherwise a ValueError exception is thrown. Any ACK payloads will remain in the TX FIFO buffer until transmitted successfully or flush_tx() is called.
  • pipe_number (int) – This will be the pipe number to use for deciding which transmissions get a response with the specified buf parameter’s data. This number must be in range [0, 5], otherwise a IndexError exception is thrown.
Returns:

True if payload was successfully loaded onto the TX FIFO buffer. False if it wasn’t because TX FIFO buffer is full.

Note

this function takes advantage of a special feature on the nRF24L01 and needs to be called for every time a customized ACK payload is to be used (not for every automatic ACK packet – this just appends a payload to the ACK packet). The ack, auto_ack, and dynamic_payloads attributes are also automatically enabled (with respect to data pipe 0) by this function when necessary.

Tip

The ACK payload must be set prior to receiving a transmission. It is also worth noting that the nRF24L01 can hold up to 3 ACK payloads pending transmission. Using this function does not over-write existing ACK payloads pending; it only adds to the queue (TX FIFO buffer) if it can. Use flush_tx() to discard unused ACK payloads when done listening.

read_ack()

RF24.read_ack()[source]

Allows user to read the automatic acknowledgement (ACK) payload (if any).

This function is an alias of recv() and remains for backward compatibility with older versions of this library.

Warning

This function will be deprecated on next major release. Use recv() instead.

irq_dr

RF24.irq_dr

A bool that represents the “Data Ready” interrupted flag. (read-only) .

Returns:
  • True represents Data is in the RX FIFO buffer
  • False represents anything depending on context (state/condition of FIFO buffers); usually this means the flag’s been reset.

Pass data_recv parameter as True to clear_status_flags() and reset this. As this is a virtual representation of the interrupt event, this attribute will always be updated despite what the actual IRQ pin is configured to do about this event.

Calling this does not execute an SPI transaction. It only exposes that latest data contained in the STATUS byte that’s always returned from any other SPI transactions. Use the update() function to manually refresh this data when needed (especially after calling clear_status_flags()).

irq_df

RF24.irq_df

A bool that represents the “Data Failed” interrupted flag. (read-only) .

Returns:
  • True signifies the nRF24L01 attemped all configured retries
  • False represents anything depending on context (state/condition); usually this means the flag’s been reset.

Pass data_fail parameter as True to clear_status_flags() and reset this. As this is a virtual representation of the interrupt event, this attribute will always be updated despite what the actual IRQ pin is configured to do about this event.

Calling this does not execute an SPI transaction. It only exposes that latest data contained in the STATUS byte that’s always returned from any other SPI transactions. Use the update() function to manually refresh this data when needed (especially after calling clear_status_flags()).

irq_ds

RF24.irq_ds

A bool that represents the “Data Sent” interrupted flag. (read-only) .

Returns:
  • True represents a successful transmission
  • False represents anything depending on context (state/condition of FIFO buffers); usually this means the flag’s been reset.

Pass data_sent parameter as True to clear_status_flags() and reset this. As this is a virtual representation of the interrupt event, this attribute will always be updated despite what the actual IRQ pin is configured to do about this event.

Calling this does not execute an SPI transaction. It only exposes that latest data contained in the STATUS byte that’s always returned from any other SPI transactions. Use the update() function to manually refresh this data when needed (especially after calling clear_status_flags()).

clear_status_flags()

RF24.clear_status_flags(data_recv=True, data_sent=True, data_fail=True)[source]

This clears the interrupt flags in the status register.

Internally, this is automatically called by send(), write(), recv(), and when listen changes from False to True.

Parameters:
  • data_recv (bool) – specifies wheather to clear the “RX Data Ready” (irq_dr) flag.
  • data_sent (bool) – specifies wheather to clear the “TX Data Sent” (irq_ds) flag.
  • data_fail (bool) – specifies wheather to clear the “Max Re-transmit reached” (irq_df) flag.

Note

Clearing the data_fail flag is necessary for continued transmissions from the nRF24L01 (locks the TX FIFO buffer when irq_df is True) despite wheather or not the MCU is taking advantage of the interrupt (IRQ) pin. Call this function only when there is an antiquated status flag (after you’ve dealt with the specific payload related to the staus flags that were set), otherwise it can cause payloads to be ignored and occupy the RX/TX FIFO buffers. See Appendix A of the nRF24L01+ Specifications Sheet for an outline of proper behavior.

power

RF24.power

This bool attribute controls the power state of the nRF24L01. This is exposed for convenience.

  • False basically puts the nRF24L01 to sleep (AKA power down mode) with ultra-low current consumption. No transmissions are executed when sleeping, but the nRF24L01 can still be accessed through SPI. Upon instantiation, this driver class puts the nRF24L01 to sleep until the MCU invokes RX/TX modes. This driver class will only power down the nRF24L01 after exiting a The with statement block.
  • True powers up the nRF24L01. This is the first step towards entering RX/TX modes (see also listen attribute). Powering up is automatically handled by the listen attribute as well as the send() and write() functions.

Note

This attribute needs to be True if you want to put radio on Standby-II (highest current consumption) or Standby-I (moderate current consumption) modes. The state of the CE pin determines which Standby mode is acheived. See Chapter 6.1.2-7 of the nRF24L01+ Specifications Sheet for more details.

tx_full

RF24.tx_full

An attribute to represent the nRF24L01’s status flag signaling that the TX FIFO buffer is full. (read-only) .

Calling this does not execute an SPI transaction. It only exposes that latest data contained in the STATUS byte that’s always returned from any other SPI transactions. Use the update() function to manually refresh this data when needed (especially after calling flush_tx()).

Returns:
  • True for TX FIFO buffer is full
  • False for TX FIFO buffer is not full. This doesn’t mean the TX FIFO buffer is empty.

update()

RF24.update()[source]

This function is only used to get an updated status byte over SPI from the nRF24L01.

Refreshing the status byte is vital to checking status of the interrupt flags, RX pipe number related to current RX payload, and if the TX FIFO buffer is full. This function returns nothing, but internally updates the irq_dr, irq_ds, irq_df, pipe, and tx_full attributes. Internally this is a helper function to send(), and resend() functions.

resend()

RF24.resend(send_only=False)[source]

Use this function to maunally re-send the previous payload in the top level (first out) of the TX FIFO buffer.

All returned data from this function follows the same patttern that send() returns with the added condition that this function will return False if the TX FIFO buffer is empty.

Parameters:send_only (bool) – This parameter only applies when the ack attribute is set to True. Pass this parameter as True if the RX FIFO is not to be manipulated. Many other libraries’ behave as though this parameter is True (e.g. The popular TMRh20 Arduino RF24 library). This parameter defaults to False. Use recv() to get the ACK payload (if there is any) from the RX FIFO.Remember that the RX FIFO can only hold up to 3 payloads at once.

Note

The nRF24L01 normally removes a payload from the TX FIFO buffer after successful transmission, but not when this function is called. The payload (successfully transmitted or not) will remain in the TX FIFO buffer until flush_tx() is called to remove them. Alternatively, using this function also allows the failed payload to be over-written by using send() or write() to load a new payload into the TX FIFO buffer.

write()

RF24.write(buf, ask_no_ack=False, write_only=False)[source]

This non-blocking function (when used as alternative to send()) is meant for asynchronous applications and can only handle one payload at a time as it is a helper function to send().

This function isn’t completely non-blocking as we still need to wait 5 ms (CSN_DELAY) for the CSN pin to settle (allowing an accurate SPI write transaction). Example usage of this function can be seen in the IRQ pin example

Parameters:
  • buf (bytearray) –

    The payload to transmit. This bytearray must have a length greater than 0 and less than 32 bytes, otherwise a ValueError exception is thrown.

    • If the dynamic_payloads attribute is disabled for data pipe 0 and this bytearray’s length is less than the payload_length attribute for data pipe 0, then this bytearray is padded with zeros until its length is equal to the payload_length attribute for data pipe 0.
    • If the dynamic_payloads attribute is disabled for data pipe 0 and this bytearray’s length is greater than payload_length attribute for data pipe 0, then this bytearray’s length is truncated to equal the payload_length attribute for data pipe 0.
  • ask_no_ack (bool) –

    Pass this parameter as True to tell the nRF24L01 not to wait for an acknowledgment from the receiving nRF24L01. This parameter directly controls a NO_ACK flag in the transmission’s Packet Control Field (9 bits of information about the payload). Therefore, it takes advantage of an nRF24L01 feature specific to individual payloads, and its value is not saved anywhere. You do not need to specify this for every payload if the arc attribute is disabled, however setting this parameter to True will work despite the arc attribute’s setting.

    Note

    Each transmission is in the form of a packet. This packet contains sections of data around and including the payload. See Chapter 7.3 in the nRF24L01 Specifications Sheet for more details.

  • write_only (bool) –

    This function will not manipulate the nRF24L01’s CE pin if this parameter is True. The default value of False will ensure that the CE pin is HIGH upon exiting this function. This function does not set the CE pin LOW at any time. Use this parameter as True to fill the TX FIFO buffer before beginning transmissions.

    Note

    The nRF24L01 doesn’t initiate sending until a mandatory minimum 10 µs pulse on the CE pin is acheived. If the write_only parameter is False, then that pulse is initiated before this function exits. However, we have left that 10 µs wait time to be managed by the MCU in cases of asychronous application, or it is managed by using send() instead of this function. According to the Specification sheet, if the CE pin remains HIGH for longer than 10 µs, then the nRF24L01 will continue to transmit all payloads found in the TX FIFO buffer.

Warning

A note paraphrased from the nRF24L01+ Specifications Sheet:

It is important to NEVER to keep the nRF24L01+ in TX mode for more than 4 ms at a time. If the [arc attribute is] enabled, nRF24L01+ is never in TX mode longer than 4 ms.

Tip

Use this function at your own risk. Because of the underlying “Enhanced ShockBurst Protocol”, disobeying the 4 ms rule is easily avoided if the arc attribute is greater than 0. Alternatively, you MUST use nRF24L01’s IRQ pin and/or user-defined timer(s) to AVOID breaking the 4 ms rule. If the nRF24L01+ Specifications Sheet explicitly states this, we have to assume radio damage or misbehavior as a result of disobeying the 4 ms rule. See also table 18 in the nRF24L01 specification sheet for calculating an adequate transmission timeout sentinal.

flush_rx()

RF24.flush_rx()[source]

A helper function to flush the nRF24L01’s RX FIFO buffer.

Note

The nRF24L01 RX FIFO is 3 level stack that holds payload data. This means that there can be up to 3 received payloads (each of a maximum length equal to 32 bytes) waiting to be read (and removed from the stack) by recv() or read_ack(). This function clears all 3 levels.

flush_tx()

RF24.flush_tx()[source]

A helper function to flush the nRF24L01’s TX FIFO buffer.

Note

The nRF24L01 TX FIFO is 3 level stack that holds payload data. This means that there can be up to 3 payloads (each of a maximum length equal to 32 bytes) waiting to be transmit by send(), resend() or write(). This function clears all 3 levels. It is worth noting that the payload data is only removed from the TX FIFO stack upon successful transmission (see also resend() as the handling of failed transmissions can be altered).

fifo()

RF24.fifo(about_tx=False, check_empty=None)[source]

This provides some precision determining the status of the TX/RX FIFO buffers. (read-only)

Parameters:
  • about_tx (bool) –
    • True means the information returned is about the TX FIFO buffer.
    • False means the information returned is about the RX FIFO buffer. This parameter defaults to False when not specified.
  • check_empty (bool) –
    • True tests if the specified FIFO buffer is empty.
    • False tests if the specified FIFO buffer is full.
    • None (when not specified) returns a 2 bit number representing both empty (bit 1) & full (bit 0) tests related to the FIFO buffer specified using the about_tx parameter.
Returns:

  • A bool answer to the question:

    ”Is the [TX/RX](about_tx) FIFO buffer [empty/full](check_empty)?

  • If the check_empty parameter is not specified: an int in range [0,2] for which:

    • 1 means the specified FIFO buffer is full
    • 2 means the specified FIFO buffer is empty
    • 0 means the specified FIFO buffer is neither full nor empty

pipe

RF24.pipe

The identifying number of the data pipe that received the next available payload in the RX FIFO buffer. (read only) .

Calling this does not execute an SPI transaction. It only exposes that latest data contained in the STATUS byte that’s always returned from any other SPI transactions. Use the update() function to manually refresh this data when needed (especially after calling flush_rx()).

Returns:
  • None if there is no payload in RX FIFO.
  • The int identifying pipe number [0,5] that received the next available payload in the RX FIFO buffer.

address_length

RF24.address_length

This int attribute specifies the length (in bytes) of addresses to be used for RX/TX pipes. A valid input value must be an int in range [3, 5]. Otherwise a ValueError exception is thrown. Default is set to the nRF24L01’s maximum of 5.

address()

RF24.address(index=-1)[source]

Returns the current address set to a specified data pipe or the TX address. (read-only)

This function returns the full content of the nRF24L01’s registers about RX/TX addresses despite what address_length is set to.

Parameters:index (int) – the number of the data pipe whose address is to be returned. A valid index ranges [0,5] for RX addresses or any negative number for the TX address. Otherwise an IndexError is thown. This parameter defaults to -1.

rpd

RF24.rpd

This read-only attribute returns True if RPD (Received Power Detector) is triggered or False if not triggered. The RPD flag is triggered in the following cases:

  1. During RX mode (when listen is True) and an arbitrary RF transmission with a gain above -64 dBm threshold is/was present.
  2. When a packet is received (instigated by the nRF24L01 used to detect/”listen” for incoming packets).

Note

See also section 6.4 of the Specification Sheet concerning the RPD flag. Ambient temperature affects the -64 dBm threshold. The latching of this flag happens differently under certain conditions.

start_carrier_wave()

RF24.start_carrier_wave()[source]

Starts a continuous carrier wave test.

This is a basic test of the nRF24L01’s TX output. It is a commonly required test for telecommunication regulations. Calling this function may introduce interference with other transceivers that use frequencies in range [2.4, 2.525] GHz. To verify that this test is working properly, use the following code on a seperate nRF24L01 transceiver:

# declare objects for SPI bus and CSN pin and CE pin
nrf. = RF24(spi, csn, ce)
# set nrf.pa_level, nrf.channel, & nrf.data_rate values to
# match the corresponding attributes on the device that is
# transmitting the carrier wave
nrf.listen = True
if nrf.rpd:
    print("carrier wave detected")

The pa_level, channel & data_rate attributes are vital factors to the success of this test. Be sure these attributes are set to the desired test conditions before calling this function. See also the rpd attribute.

Note

To preserve backward compatibility with non-plus variants of the nRF24L01, this function will also change certain settings if is_plus_variant is False. These settings changes include disabling crc, disabling auto_ack, disabling arc, setting ard to 250 microseconds, changing the TX address to b"\xFF\xFF\xFF\xFF\xFF", and loading a 32-byte payload (each byte is 0xFF) into the TX FIFO buffer while continuously behaving like resend() to establish the constant carrier wave. If is_plus_variant is True, then none of these changes are needed nor applied.

stop_carrier_wave()

RF24.stop_carrier_wave()[source]

Stops a continuous carrier wave test.

See start_carrier_wave() for more details.

Note

Calling this function puts the nRF24L01 to sleep (AKA power down mode).

Configuration API

CSN_DELAY

circuitpython_nrf24l01.rf24.CSN_DELAY = 0.005

The delay time (in seconds) used to let the CSN pin settle, allowing a clean SPI transaction.

dynamic_payloads

RF24.dynamic_payloads

This bool attribute controls the nRF24L01’s dynamic payload length feature for each pipe. Default setting is enabled on all pipes.

  • True or 1 enables nRF24L01’s dynamic payload length feature for all data pipes. The payload_length attribute is ignored when this feature is enabled for all respective data pipes.
  • False or 0 disables nRF24L01’s dynamic payload length feature for all data pipes. Be sure to adjust the payload_length attribute accordingly when this feature is disabled for any respective data pipes.
  • A list or tuple containing booleans or integers can be used control this feature per data pipe. Index 0 controls this feature on data pipe 0. Indices greater than 5 will be ignored since there are only 6 data pipes. If any index’s value is less than 0 (a negative value), then the pipe corresponding to that index will remain unaffected.

Note

This attribute mostly relates to RX operations, but data pipe 0 applies to TX operations also. The auto_ack attribute is automatically enabled by this attribute for any data pipes that have this feature enabled. Disabling this feature for any data pipe will not affect the auto_ack feature for the corresponding data pipes.

payload_length

RF24.payload_length

This int attribute specifies the length (in bytes) of static payloads for each pipe. If the dynamic_payloads attribute is enabled for a certain data pipe, this attribute has no affect on that data pipe. When dynamic_payloads is disabled for a certain data pipe, this attribute is used to specify the payload length on that data pipe.

A valid input value must be:

  • an int in range [1, 32]. Otherwise a ValueError exception is thrown.
  • A list or tuple containing integers can be used control this feature per data pipe. Index 0 controls this feature on data pipe 0. Indices greater than 5 will be ignored since there are only 6 data pipes. If any index’s value is 0, then the existing setting will persist (not be changed).

Default is set to the nRF24L01’s maximum of 32 (on all data pipes).

Note

This attribute mostly relates to RX operations, but data pipe 0 applies to TX operations also.

auto_ack

RF24.auto_ack

This bool attribute controls the nRF24L01’s automatic acknowledgment feature during the process of receiving a packet. Default setting is enabled on all data pipes.

  • True or 1 enables transmitting automatic acknowledgment packets for all data pipes. The CRC (cyclic redundancy checking) is enabled (for all transmissions) automatically by the nRF24L01 if this attribute is enabled for any data pipe (see also crc attribute).
  • False or 0 disables transmitting automatic acknowledgment packets for all data pipes. The crc attribute will remain unaffected when disabling this attribute for any data pipes.
  • A list or tuple containing booleans or integers can be used control this feature per data pipe. Index 0 controls this feature on data pipe 0. Indices greater than 5 will be ignored since there are only 6 data pipes. If any index’s value is less than 0 (a negative value), then the pipe corresponding to that index will remain unaffected.

Note

This attribute mostly relates to RX operations, but data pipe 0 applies to TX operations also.

arc

RF24.arc

This int attribute specifies the nRF24L01’s number of attempts to re-transmit TX payload when acknowledgment packet is not received. The auto_ack attribute must be enabled on the receiving nRF24L01 respective data pipe, otherwise this attribute will make send() seem like it failed.

A valid input value must be in range [0, 15]. Otherwise a ValueError exception is thrown. Default is set to 3. A value of 0 disables the automatic re-transmit feature and considers all payload transmissions a success.

ard

RF24.ard

This int attribute specifies the nRF24L01’s delay (in microseconds) between attempts to automatically re-transmit the TX payload when an expected acknowledgement (ACK) packet is not received. During this time, the nRF24L01 is listening for the ACK packet. If the auto_ack attribute is disabled, this attribute is not applied.

A valid input value must be in range [250, 4000]. Otherwise a ValueError exception is thrown. Default is 1500 for reliability. If this is set to a value that is not multiple of 250, then the highest multiple of 250 that is no greater than the input value is used.

Note

Paraphrased from nRF24L01 specifications sheet:

Please take care when setting this parameter. If the custom ACK payload is more than 15 bytes in 2 Mbps data rate, the ard must be 500µS or more. If the custom ACK payload is more than 5 bytes in 1 Mbps data rate, the ard must be 500µS or more. In 250kbps data rate (even when there is no custom ACK payload) the ard must be 500µS or more.

See data_rate attribute on how to set the data rate of the nRF24L01’s transmissions.

ack

RF24.ack

This bool attribute represents the status of the nRF24L01’s capability to use custom payloads as part of the automatic acknowledgment (ACK) packet. Use this attribute to set/check if the custom ACK payloads feature is enabled. Default setting is False.

  • True enables the use of custom ACK payloads in the ACK packet when responding to receiving transmissions.
  • False disables the use of custom ACK payloads in the ACK packet when responding to receiving transmissions.

Important

As dynamic_payloads and auto_ack attributes are required for this feature to work, they are automatically enabled (on data pipe 0) as needed. However, it is required to enable the auto_ack and dynamic_payloads features on all applicable pipes. Disabling this feature does not disable the auto_ack and dynamic_payloads attributes for any data pipe; they work just fine without this feature.

interrupt_config()

RF24.interrupt_config(data_recv=True, data_sent=True, data_fail=True)[source]

Sets the configuration of the nRF24L01’s IRQ pin. (write-only)

The digital signal from the nRF24L01’s IRQ (Interrupt ReQuest) pin is active LOW.

Parameters:
  • data_recv (bool) – If this is True, then IRQ pin goes active when new data is put into the RX FIFO buffer. Default setting is True
  • data_sent (bool) – If this is True, then IRQ pin goes active when a payload from TX buffer is successfully transmit. Default setting is True
  • data_fail (bool) – If this is True, then IRQ pin goes active when the maximum number of attempts to re-transmit the packet have been reached. If arc attribute is disabled, then this IRQ event is not used. Default setting is True

Note

To fetch the status (not configuration) of these IRQ flags, use the irq_df, irq_ds, irq_dr attributes respectively.

Tip

Paraphrased from nRF24L01+ Specification Sheet:

The procedure for handling irq_dr IRQ should be:

  1. retreive the payload from RX FIFO using recv()
  2. clear irq_dr status flag (taken care of by using recv() in previous step)
  3. read FIFO_STATUS register to check if there are more payloads available in RX FIFO buffer. A call to pipe (may require update() to be called beforehand), any() or even (False, True) as parameters to fifo() will get this result.
  4. if there is more data in RX FIFO, repeat from step 1

data_rate

RF24.data_rate

This int attribute specifies the nRF24L01’s frequency data rate for OTA (over the air) transmissions. A valid input value is:

  • 1 sets the frequency data rate to 1 Mbps
  • 2 sets the frequency data rate to 2 Mbps
  • 250 sets the frequency data rate to 250 Kbps (see warning below)

Any invalid input throws a ValueError exception. Default is 1 Mbps.

Warning

250 Kbps is not available for the non-plus variants of the nRF24L01 transceivers. Trying to set the data rate to 250 kpbs when is_plus_variant is True will throw a NotImplementedError.

channel

RF24.channel

This int attribute specifies the nRF24L01’s frequency. A valid input value must be in range [0, 125] (that means [2.4, 2.525] GHz). Otherwise a ValueError exception is thrown. Default is 76 (2.476 GHz).

crc

RF24.crc

This int attribute specifies the nRF24L01’s CRC (cyclic redundancy checking) encoding scheme in terms of byte length. CRC is a way of making sure that the transmission didn’t get corrupted over the air.

A valid input value must be:

  • 0 disables CRC (no anti-corruption of data)
  • 1 enables CRC encoding scheme using 1 byte (weak anti-corruption of data)
  • 2 enables CRC encoding scheme using 2 bytes (better anti-corruption of data)

Any invalid input throws a ValueError exception. Default is enabled using 2 bytes.

Note

The nRF24L01 automatically enables CRC if automatic acknowledgment feature is enabled (see auto_ack attribute) for any data pipe.

pa_level

RF24.pa_level

This int attribute specifies the nRF24L01’s power amplifier level (in dBm). Higher levels mean the transmission will cover a longer distance. Use this attribute to tweak the nRF24L01 current consumption on projects that don’t span large areas.

A valid input value is:

  • -18 sets the nRF24L01’s power amplifier to -18 dBm (lowest)
  • -12 sets the nRF24L01’s power amplifier to -12 dBm
  • -6 sets the nRF24L01’s power amplifier to -6 dBm
  • 0 sets the nRF24L01’s power amplifier to 0 dBm (highest)

If this attribute is set to a list or tuple, then the list/tuple must contain the desired power amplifier level (from list above) at index 0 and a bool to control the Low Noise Amplifier (LNA) feature at index 1. All other indices will be discarded.

Note

The LNA feature setting only applies to the nRF24L01 (non-plus variant).

Any invalid input will invoke the default of 0 dBm with LNA enabled.

is_lna_enabled

RF24.is_lna_enabled

A read-only bool attribute about the LNA (Low Noise Amplifier) gain feature. See pa_level attribute about how to set this. Default is always enabled, but this feature is specific to non-plus variants of nRF24L01 transceivers. If is_plus_variant attribute is True, then setting feature in any way has no affect.

BLE Limitations

This module uses the RF24 class to make the nRF24L01 imitate a Bluetooth-Low-Emissions (BLE) beacon. A BLE beacon can send data (referred to as advertisements) to any BLE compatible device (ie smart devices with Bluetooth 4.0 or later) that is listening.

Original research was done by Dmitry Grinberg and his write-up (including C source code) can be found here As this technique can prove invaluable in certain project designs, the code here has been adapted to work with CircuitPython.

Important

Because the nRF24L01 wasn’t designed for BLE advertising, it has some limitations that helps to be aware of.

  1. The maximum payload length is shortened to 18 bytes (when not broadcasting a device name nor the nRF24L01 show_pa_level). This is calculated as:

    32 (nRF24L01 maximum) - 6 (MAC address) - 5 (required flags) - 3 (CRC checksum) = 18

    Use the helper function available() to detirmine if your payload can be transmit.

  2. the channels that BLE use are limited to the following three: 2.402 GHz, 2.426 GHz, and 2.480 GHz. We have provided a tuple of these specific channels for convenience (See BLE_FREQ and hop_channel()).

  3. crc is disabled in the nRF24L01 firmware because BLE specifications require 3 bytes (crc24_ble()), and the nRF24L01 firmware can only handle a maximum of 2. Thus, we have appended the required 3 bytes of CRC24 into the payload.

  4. address_length of BLE packet only uses 4 bytes, so we have set that accordingly.

  5. The auto_ack (automatic acknowledgment) feature of the nRF24L01 is useless when tranmitting to BLE devices, thus it is disabled as well as automatic re-transmit (arc) and custom ACK payloads (ack) features which both depend on the automatic acknowledgments feature.

  6. The dynamic_payloads feature of the nRF24L01 isn’t compatible with BLE specifications. Thus, we have disabled it.

  7. BLE specifications only allow using 1 Mbps RF data_rate, so that too has been hard coded.

  8. Only the “on data sent” (irq_ds) & “on data ready” (irq_dr) events will have an effect on the interrupt (IRQ) pin. The “on data fail” (irq_df) is never triggered because arc attribute is disabled.

helpers

swap_bits()

circuitpython_nrf24l01.fake_ble.swap_bits(original)[source]

This function reverses the bit order for a single byte.

Returns:An int containing the byte whose bits are reversed compared to the value passed to the original parameter.
Parameters:original (int) – This should be a single unsigned byte, meaning the parameters value can only range from 0 to 255.

reverse_bits()

circuitpython_nrf24l01.fake_ble.reverse_bits(original)[source]

This function reverses the bit order for an entire buffer protocol object.

Returns:A bytearray whose byte order remains the same, but each byte’s bit order is reversed.
Parameters:original (bytearray,bytes) – The original buffer whose bits are to be reversed.

chunk()

circuitpython_nrf24l01.fake_ble.chunk(buf, data_type=22)[source]

This function is used to pack data values into a block of data that make up part of the BLE payload per Bluetooth Core Specifications.

Parameters:
  • buf (bytearray,bytes) – The actual data contained in the block.
  • data_type (int) – The type of data contained in the chunk. This is a predefined number according to BLE specifications. The default value 0x16 describes all service data. 0xFF describes manufacturer information. Any other values are not applicable to BLE advertisements.

Important

This function is called internally by advertise(). To pack multiple data values into a single payload, use this function for each data value and pass a list or tuple of the returned results to advertise() (see example code in documentation about advertise() for more detail). Remember that broadcasting multiple data values may require the name be set to None and/or the show_pa_level be set to False for reasons about the payload size with BLE Limitations.

crc24_ble()

circuitpython_nrf24l01.fake_ble.crc24_ble(data, deg_poly=1627, init_val=5592405)[source]

This function calculates a checksum of various sized buffers.

This is exposed for convenience but should not be used for other buffer protocols that require big endian CRC24 format.

Parameters:
  • data (bytearray,bytes) – The buffer of data to be uncorrupted.
  • deg_poly (int) – A preset “degree polynomial” in which each bit represents a degree who’s coefficient is 1. BLE specfications require 0x00065b (default value).
  • init_val (int) – This will be the initial value that the checksum will use while shifting in the buffer data. BLE specfications require 0x555555 (default value).
Returns:

A 24-bit bytearray representing the checksum of the data (in proper little endian).

BLE_FREQ

circuitpython_nrf24l01.fake_ble.BLE_FREQ = (2, 26, 80)

The BLE channel number is different from the nRF channel number. This tuple contains the relative predefined channels used:

  • nRF channel 2 == BLE channel 37
  • nRF channel 26 == BLE channel 38
  • nRF channel 80 == BLE channel 39

FakeBLE class

class circuitpython_nrf24l01.fake_ble.FakeBLE(spi, csn, ce, spi_frequency=10000000)[source]

A class to implement BLE advertisements using the nRF24L01.

Per the limitations of this technique, only some of underlying RF24 functionality is available for configuration when implementing BLE transmissions. See the Available RF24 functionality for more details.

Parameters:
  • spi (SPI) –

    The object for the SPI bus that the nRF24L01 is connected to.

    Tip

    This object is meant to be shared amongst other driver classes (like adafruit_mcp3xxx.mcp3008 for example) that use the same SPI bus. Otherwise, multiple devices on the same SPI bus with different spi objects may produce errors or undesirable behavior.

  • csn (DigitalInOut) – The digital output pin that is connected to the nRF24L01’s CSN (Chip Select Not) pin. This is required.
  • ce (DigitalInOut) – The digital output pin that is connected to the nRF24L01’s CE (Chip Enable) pin. This is required.
  • spi_frequency (int) – Specify which SPI frequency (in Hz) to use on the SPI bus. This parameter only applies to the instantiated object and is made persistent via SPIDevice.

to_android

FakeBLE.to_android

A bool attribute to specify if advertisements should be compatible with Android smartphones. A value of True allows advertisements to be compatible with Android smartphones. Setting this attribute to False still allows advertisements to be compatible with anything else except Android smartphones. Default Value is True.

Warning

This attribute will be deprecated on the next major release because it is not necessary to change this attribute. Changing this attribute to False only breaks compatibility with Android smartphones.

mac

FakeBLE.mac

This attribute returns a 6-byte buffer that is used as the arbitrary mac address of the BLE device being emulated. You can set this attribute using a 6-byte int or bytearray. If this is set to None, then a random 6-byte address is generated.

name

FakeBLE.name

The broadcasted BLE name of the nRF24L01. This is not required. In fact setting this attribute will subtract from the available payload length (in bytes). Set this attribute to None to disable advertising the device name.

Note

This information occupies (in the TX FIFO) an extra 2 bytes plus the length of the name set by this attribute.

show_pa_level

FakeBLE.show_pa_level

If this attribute is True, the payload will automatically include the nRF24L01’s pa_level in the advertisement. The default value of False will exclude this optional information.

Note

This information occupies (in the TX FIFO) an extra 3 bytes, and is really only useful for some applications to calculate proximity to the nRF24L01 transceiver.

hop_channel()

FakeBLE.hop_channel()[source]

Trigger an automatic change of BLE compliant channels.

whiten()

FakeBLE.whiten(data)[source]

Whitening the BLE packet data ensures there’s no long repeatition of bits.

This is done according to BLE specifications.

Parameters:data (bytearray,bytes) – The packet to whiten.
Returns:A bytearray of the data with the whitening algorythm applied.

Warning

This function uses the currently set BLE channel as a base case for the whitening coefficient. Do not call hop_channel() before using this function to de-whiten received payloads (which isn’t officially supported yet). Note that advertise() uses this function internally to prevent such improper usage.

available()

FakeBLE.available(hypothetical=b'')[source]

This function will calculates how much length (in bytes) is available in the next payload.

This is detirmined from the current state of name and show_pa_level attributes.

Parameters:hypothetical (bytearray,bytes) – Pass a potential chunk() of data to this parameter to calculate the resulting left over length in bytes. This parameter is optional.
Returns:An int representing the length of available bytes for the a single payload.

Available RF24 functionality

pa_level

FakeBLE.pa_level

See pa_level for more details.

channel

FakeBLE.channel

The only allowed channels are those contained in the BLE_FREQ tuple.

payload_length

FakeBLE.payload_length

This attribute is best left at 32 bytes for all BLE operations.

power

FakeBLE.power

See power for more details.

is_lna_enabled

FakeBLE.is_lna_enabled

See is_lna_enabled for more details.

is_plus_variant

FakeBLE.is_plus_variant

See is_plus_variant for more details.

interrupt_config()

FakeBLE.interrupt_config()[source]

See interrupt_config() for more details.

Warning

The irq_df attribute (and also this function’s data_fail parameter) is not implemented for BLE operations.

irq_ds

FakeBLE.irq_ds

See irq_ds for more details.

irq_dr

FakeBLE.irq_dr

See irq_dr for more details.

clear_status_flags()

FakeBLE.clear_status_flags()[source]

See clear_status_flags() for more details.

update()

FakeBLE.update()[source]

See update() for more details.

what_happened()

FakeBLE.what_happened()[source]

See what_happened() for more details.

Indices and tables