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 Python.
Because the nRF24L01 wasn’t designed for BLE advertising, it has some limitations that helps to be aware of.
32 (nRF24L01 maximum) - 6 (MAC address) - 5 (required flags) - 3 (CRC checksum) = 18
Use the helper function
len_available()to determine if your payload can be transmit.
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
crc_lengthis 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.
address_widthof BLE packet only uses 4 bytes, so we have set that accordingly.
The auto-ack (automatic acknowledgment) feature of the nRF24L01 is useless when transmitting to BLE devices, thus it is disabled as well as automatic re-transmit (
get_arc()) and custom ACK payloads (
ack_payloads) features which both depend on the automatic acknowledgments feature.
dynamic_payloadsfeature of the nRF24L01 isn’t compatible with BLE specifications. Thus, we have disabled it.
BLE specifications only allow using 1 Mbps RF
data_rate, so that too has been hard coded.
Only the “on data sent” & “on data ready” events will have an effect on the interrupt (IRQ) pin. The “on data fail” is never triggered because auto-ack feature is disabled. Keep this in mind when using
fake_ble module helpers¶
pyrf24.fake_ble.address_repr(buf, reverse: bool =
True, delimit: str =
'') str ¶
Convert a buffer into a hexlified string.
This method is primarily used to display how the address is used by the radio.
>>> from pyrf24.fake_ble import address_repr >>> address_repr(b"1Node") '65646F4E31'
- buf : bytes,bytearray¶
The buffer of bytes to convert into a hexlified string.
- reverse : bool¶
boolto control the resulting endianess.
Trueoutputs the result as big endian.
Falseoutputs the result as little endian. This parameter defaults to
bytesobjects are stored in big endian but written in little endian.
- delimit : str¶
A string of hexadecimal characters in big endian form of the specified
- pyrf24.fake_ble.swap_bits(original: int) int ¶
This function reverses the bit order for a single byte.
- pyrf24.fake_ble.reverse_bits(original: bytes | bytearray) bytearray ¶
This function reverses the bit order for an entire buffer protocol object.
pyrf24.fake_ble.crc24_ble(data: bytes | bytearray, deg_poly: int =
1627, init_val: int =
5592405) bytearray ¶
This function calculates a checksum of various sized buffers.
This is exposed for convenience and should not be used for other buffer protocols that require big endian CRC24 format.
- 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 specifications require
- init_val : int¶
This will be the initial value that the checksum will use while shifting in the buffer data. BLE specifications require
bytearrayrepresenting the checksum of the data (in proper little endian).
pyrf24.fake_ble.chunk(buf: bytes | bytearray, data_type: int =
22) bytearray ¶
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.
- 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
0x16describes all service data.
0xFFdescribes manufacturer information. Any other values are not applicable to BLE advertisements.
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
tupleof the returned results to
advertise()(see example code in documentation about
advertise()for more detail). Remember that broadcasting multiple data values may require the
namebe set to
show_pa_levelbe set to
Falsefor reasons about the payload size with BLE Limitations.
- pyrf24.fake_ble.whitener(buf: bytes | bytearray, coefficient: int) bytearray ¶
Whiten and de-whiten data according to the given coefficient.
- buf : bytes,bytearray¶
The BLE payloads data. This data should include the CRC24 checksum.
- coefficient : int¶
The whitening coefficient used to avoid repeating binary patterns. This is the index (plus 37) of
BLE_FREQtuple for nRF24L01 channel that the payload transits.
rx_channel = radio.channel coef = ( index + 37 for index, chl in enumerate(BLE_FREQ) if chl == rx_channel )
If currently used nRF24L01 channel is different from the channel in which the payload was received, then set this parameter accordingly.
(2, 26, 80)¶
The BLE channel number is different from the nRF channel number.
This tuple contains the relative predefined channels used:
- class pyrf24.fake_ble.QueueElement(buffer: bytes | bytearray)¶
A data structure used for storing received & decoded BLE payloads in the
- data : list[bytearray | bytes | BatteryServiceData | TemperatureServiceData | UrlServiceData]¶
listof the transmitting device’s data structures (if any). If an element in this
listis not an instance (or descendant) of the
ServiceDataclass, then it is likely a custom, user-defined, or unsupported specification - in which case it will be a
- name : bytes | str | None¶
- class pyrf24.fake_ble.FakeBLE(radio: RF24)¶
A class to implement BLE advertisements using the nRF24L01.
Per the limitations of this technique, only some of underlying
RF24functionality is available for configuration when implementing BLE transmissions. See the Restricted RF24 functionality for more details.
advertise(buf: bytes | bytearray =
b'', data_type: int =
This blocking function is used to broadcast a payload.
Nothing as every transmission will register as a success under the required settings for BLE beacons.
- buf : bytearray¶
The payload to transmit. This bytearray must have a length greater than 0 and less than 22 bytes Otherwise a
ValueErrorexception is thrown whose prompt will tell you the maximum length allowed under the current configuration. This can also be a list or tuple of payloads (
bytearray); in which case, all items in the list/tuple are processed are packed into 1 payload for a single transmissions. See example code below about passing a
tupleto this parameter.
- data_type : int¶
This is used to describe the buffer data passed to the
0x16describes all service data. The default value
0xFFdescribes manufacturer information. This parameter is ignored when a
listis passed to the
bufparameter. Any other values are not applicable to BLE advertisements.
To pass multiple data values to the
bufparameter see the following code as an example:
# let UUIDs be the 16-bit identifier that corresponds to the # BLE service type. The following values are not compatible with # BLE advertisements. UUID_1 = 0x1805 UUID_2 = 0x1806 service1 = ServiceData(UUID_1) service2 = ServiceData(UUID_2) service1.data = b"some value 1" service2.data = b"some value 2" # make a tuple of the buffers buffers = ( chunk(service1.buffer), chunk(service2.buffer) ) # let `ble` be the instantiated object of the FakeBLE class ble.advertise(buffers) ble.hop_channel()
- available() bool ¶
This method will take the first available data from the radio’s RX FIFO and validate the payload using the 24bit CRC checksum at the end of the payload. If the payload is indeed a valid BLE transmission that fit within the 32 bytes that the nRF24L01 can capture, then this method will decipher the data within the payload and enqueue the resulting
read()to fetch the decoded data.
begin(ce_pin: int | None =
None, csn_pin: int | None =
None) bool ¶
Initialize the radio using BLE specifications.
Internally, this function also calls
begin(), so there’s no need to initialized the radio’s hardware before calling this function.
If dynamically specifying the radio’s GPIO pins, then 2 positional arguments are supported.
Trigger an automatic change of BLE compliant channels.
b'') int ¶
This function will calculates how much length (in bytes) is available in the next payload.
- property mac¶
This attribute returns a 6-byte buffer that is used as the arbitrary mac address of the BLE device being emulated.
- property 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
Noneto disable advertising the device name.
This information occupies (in the TX FIFO) an extra 2 bytes plus the length of the name set by this attribute.
- read() QueueElement | None ¶
Get the First Out element from the queue.
The internal cache used when validating received BLE payloads.
This attribute is only used by
available()to cache the data from the top level of the radio’s RX FIFO then validate and decode it.
This attribute is exposed for debugging purposes.
- rx_queue : list[QueueElement]¶
The internal queue of received BLE payloads’ data.
This attribute is exposed for debugging purposes, but it can also be used by applications.
- property show_pa_level : bool¶
The default value of
Falsewill exclude this optional information.
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.
Restricted RF24 functionality¶
Service related classes¶
- class pyrf24.fake_ble.ServiceData(uuid)¶
An abstract helper class to package specific service data using Bluetooth SIG defined 16-bit UUID flags to describe the data type.
- __len__() int ¶
For convenience, this class is compatible with python’s builtin
len()method. In this context, this will return the length of the object (in bytes) as it would appear in the advertisement payload.
- __repr__() str ¶
For convenience, this class is compatible with python’s builtin
repr()method. In this context, it will return a string of data with applicable suffixed units.
- property buffer : bytes¶
Get the representation of the instantiated object as an immutable
- property data : float | int | str | bytes | bytearray¶
Service data UUID numbers¶
These are the 16-bit UUID numbers used by the Derivative Children of the ServiceData class
- pyrf24.fake_ble.TEMPERATURE_UUID = 0x1809¶
The Temperature Service UUID number
- pyrf24.fake_ble.BATTERY_UUID = 0x180F¶
The Battery Service UUID number
- pyrf24.fake_ble.EDDYSTONE_UUID = 0xFEAA¶
The Eddystone Service UUID number
- class pyrf24.fake_ble.TemperatureServiceData¶
Bluetooth Health Thermometer Measurement format as defined in the GATT Specifications Supplement.
- class pyrf24.fake_ble.BatteryServiceData¶
This derivative of the
ServiceDataclass can be used to represent battery charge percentage as a 1-byte value.
The Bluetooth Battery Level format as defined in the GATT Specifications Supplement.
- class pyrf24.fake_ble.UrlServiceData¶
Google’s Eddystone-URL specifications.