I am working on building nrf24 modules Network using the RF24Network Library .
I need around 100 sensor_nodes to be in this Network sending their data to the Master which will then store their data to Cloud.
But I tested a network with 10 sensor_nodes to begin with , and I am unable to get data from all the nodes most of the times.
I have researched alot about the nrf24 modules and rf24Network Library, somewhere I read that you can connect upto 781 nodes while on few blog posts I read you can connect 30125 nodes on a single network.I know this is in ideal condition(which is never possible). But I thought I can atleast I would be able to connect 100 nodes in a network.
But I am starting to think even that is not possible.
can someone please clear why this is happening?
what might be the potential issues that this is not working?
the Masters code remains same while the nodes code changes slightly for every node.
- I am using esp8266 for now, but in future I am planning to use esp32 Microcontroller for all the nodes and master.
- After uploading the code for this testing, I powered them using a extension board which have around 7 USB ports in it and 2 mobile adapters .
- I kept them around 60-70 cm apart from each other.
- I tested this 10 nodes in my House. I did a test with 2 nrf24l01+PA+LNA modules in an open area and I got their range around 1.1 Km(I am really proud of that test).
- Master transmits a Multicast Message every 1 minute , and then each node after receiving the msg, transmit after a random_delay(0 to 6 seconds).
My code:
//Master Node
#include <RF24Network.h>
#include <RF24.h>
#include <SPI.h>
/* Sketch to send message to MQTT Broker on Cloud */
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
// These variables store the WiFi credentials and MQTT server information.
//const char* ssid = "PRATIK";
//const char* password = "asdfghjkl1231";
const char* mqtt_server = "dev.PRATIK.in";
int mqtt_port = 1883;
// These objects are used to establish and manage connections to the WiFi network and MQTT broker.
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);
#define CE_pin D0
#define CSN_pin D1
// These objects are used for configuring and managing the NRF24L01+ radio module and the RF24Network layer respectively.
RF24 radio(CE_pin, CSN_pin);
RF24Network network(radio); // Include the radio in the network
#define RF_channel 120
const uint16_t this_node = 00; // Address of this node in Octal format ( 04,031, etc)
// Format the data to be sent in the desired structure
String formatData(String code, uint16_t from_node, String command, String message) {
return code + "-" + String(from_node) + "-" + command + "-" + message + "$";
}
uint8_t level = 1;
String all = formatData("xYaZ", this_node, "rollcall", "get_data");
#define MAX_DATA_SIZE 32 // Define a maximum data size to receive
char all_ack_buffer[MAX_DATA_SIZE] = ""; // RECEIVING VARIABLE when the msg multicasted to all
unsigned long currentTime = 0;
unsigned long lastTransmissionTime = 0;
const unsigned long transmissionTimeout = 1000; // Timeout duration in milliseconds for turning OFF the LED
unsigned long Delay = 10;
#define redLED D3 //if transmission done
#define blueLED D4 // if reception done
void setup() {
setupWifi(); // setup WiFi connection
setupMqtt(); // setup mqtt connection
SPI.begin();
radio.begin();
// Configure retries for more robust communication:
radio.setRetries(10,5); // delay(microSeconds)(steps of 250us) , count
// delay: How long to wait between each retry, in multiples of 250us, max is 15. 0 means 250us, 15 means 4000us, count: How many retries before giving up, max 15
network.begin(RF_channel, this_node);
radio.setDataRate(RF24_250KBPS);
radio.setPALevel(RF24_PA_MAX);
radio.setAutoAck(true); // Disable auto-acknowledgment for pipe 0 (multicast)
radio.enableDynamicPayloads(); // Enable dynamic payloads:
radio.setCRCLength(RF24_CRC_16); // length: RF24_CRC_8 for 8-bit or RF24_CRC_16 for 16-bit Cyclic Redundancy Check (Error checking)
Serial.begin(115200);
//radio.printDetails(); // Print detailed radio configuration
pinMode(redLED, OUTPUT);
pinMode(blueLED, OUTPUT);
}
void setupWifi() { // Connects to the specified WiFi network.
WiFi.begin(ssid, password);
while ( WiFi.status() != WL_CONNECTED ) {
delay(500);
Serial.print(".");
}
}
void setupMqtt() { // This function is used to set up the MQTT connection with the broker and specify the callback function to handle incoming messages.
mqttClient.setServer(mqtt_server, mqtt_port);
// invoke "callback()" function when there is an incoming message
mqttClient.setCallback(callback);
}
void reconnect() {
while ( !mqttClient.connected() ) {
String clientId = String(ESP.getChipId()); // retrieves the ESP8266's chip ID using ESP.getChipId() and converts it into a string. The chip ID is typically a unique identifier for each ESP8266 device.
if ( mqttClient.connect(clientId.c_str() ) ) {
// attempts to connect to the MQTT broker using the previously generated client ID.
// mqttClient.connect() is a method provided by the PubSubClient library to establish a connection to the broker. It returns true if the connection is successful.
Serial.println("connected");
}
// subscribe to an MQTT topic
mqttClient.subscribe("node00"); // Subscribing to a topic allows the client to receive messages published to that topic by other clients.
}
}
void loop() {
if (!mqttClient.connected()) {
reconnect();
}
network.update();
print_all_ACK();
mqttClient.loop(); // This method is responsible for handling any incoming MQTT messages. When a message arrives, it triggers the callback function.
delay(Delay);
}
void callback(char* topic, byte* payload, unsigned int length) { // The callback function is invoked automatically whenever a message is received from the MQTT broker.
for (int i = 0; i < length; i++) { // starts a for loop that iterates over each byte of the payload data.
Serial.print((char)payload[i]);
}
payload[length] = '\0'; // adds a null terminator at the end of the payload data, effectively terminating it as a string. This step is necessary if you plan to treat the payload data as a C-style string.
// act on the incoming command
if(strcmp( ( (char *)payload ), "rollcall") == 0) { // checks if the received message matches the string "rollcall".
// "strcmp" is a C standard library function used to compare strings. If the comparison returns 0 (indicating a match), the condition is true, and the code block inside the if statement is executed.
//Send the message(Multicast) to all
send_all();
delay(Delay);
}
}
void print_all_ACK() {
network.update();
// Receiving all_ack_buffer //
if (network.available()) {
network.update();
RF24NetworkHeader header;
network.read(header, &all_ack_buffer, sizeof(all_ack_buffer));
delay(10);
digitalWrite(blueLED,HIGH);
// Process the received data in a structured manner
String receivedData = String(all_ack_buffer);
int delimiterIndex = receivedData.indexOf('$'); //The indexOf() function returns the position of the first occurrence of '$' within the String. If the character '$' is not found, it returns -1.
if(delimiterIndex != -1) {
String parsedData = receivedData.substring(0, delimiterIndex); // Extract the part before '$'
// Split the parsed data using the '-' delimiter
int hyphenIndex = parsedData.indexOf('-');
String code = parsedData.substring(0, hyphenIndex); // extracts the "code" from the whole received String
parsedData.remove(0, hyphenIndex + 1); // Remove the part before the first hyphen
hyphenIndex = parsedData.indexOf('-'); // Split the parsed data using the '-' delimiter
String from_node_str = parsedData.substring(0, hyphenIndex);
uint16_t from_node = from_node_str.toInt(); //Converts the 'to_node_str' String into an unsigned integer (uint16_t) value,
parsedData.remove(0, hyphenIndex + 1); // Remove the part before the second hyphen
String command = parsedData;
// Now 'code', 'from_node', 'command' variables contain the parsed values
// You can use these variables as needed
Serial.print(" Received from node: ");
Serial.print(from_node);
Serial.print(" | code: ");
Serial.print(code);
Serial.print(" | with command: ");
Serial.println(command);
if(code == "xYaZ") {
//Serial.print("all_ACK Received: ");
//Serial.println(all_ack_buffer);
String value = String(all_ack_buffer);
mqttClient.publish("node", value.c_str());
}
}
lastTransmissionTime = millis();
}
// Check for timeout to clear the buffer
currentTime = millis(); //Updates currentTime1 with the current value of millis().
if ((currentTime - lastTransmissionTime) > transmissionTimeout) {
// memset(void* ptr, int value, size_t num); SYNTAX
memset(all_ack_buffer, 0, sizeof(all_ack_buffer)); // uses the memset(memory set) function to set a block of memory with a specified value.
digitalWrite(blueLED, LOW);
}
}
void send_all() {
network.update();
RF24NetworkHeader header1; // (Address where the data is going)
bool ok = network.multicast(header1, &all[0], all.length(), level); // Send the data
delay(10);
digitalWrite(redLED, HIGH);
//Serial.println(all.length()); // Print the size of the transmitted message
if (ok) {
Serial.print(" sent: ");
Serial.println(all);
} else {
Serial.println("failed");
digitalWrite(redLED,LOW);
}
}
//Node01
#include <RF24Network.h>
#include <RF24.h>
#include <SPI.h>
#define CE_pin D0
#define CSN_pin D1
RF24 radio(CE_pin, CSN_pin);
RF24Network network(radio); // Include the radio in the network
#define RF_channel 120
const uint16_t this_node = 01; // Address of this node in Octal format
// Format the data to be sent in the desired structure
String getdata(String code, uint16_t from_node, String command ) {
return code + "-" + String(from_node) + "-" + command + "$";
}
String gaveData = getdata("xYaZ", 1, "rollcall");
// Define the addresses of the child nodes
const uint16_t child_nodes[5] = {011, 021, 03, 041, 051}; // The addresses of the child nodes are defined in the child_nodes array.
//const int num_child_nodes = sizeof(child_nodes) / sizeof(uint16_t); // The number of child nodes is calculated using the size of the child_nodes array(10 bytes) divided by the size of uint16_t(2 bytes).
const uint16_t master_node = 00; // Address of master node in Octal format
unsigned long currentTime = 0;
unsigned long lastTransmissionTime = 0;
const unsigned long transmissionTimeout = 2000; // Timeout duration in milliseconds
char received_msg[32] = "";
uint8_t level = 2; // level where we want to Mulicast the message
#define ledPin D4
void setup() {
SPI.begin();
radio.begin();
// Configure retries for more robust communication:
radio.setRetries(8,5); // delay(microSeconds)(steps of 250us) , count
network.begin(RF_channel, this_node);
radio.setDataRate(RF24_250KBPS);
radio.setPALevel(RF24_PA_MAX);
// Enable dynamic payloads:
radio.enableDynamicPayloads();
radio.setCRCLength(RF24_CRC_16); // length: RF24_CRC_8 for 8-bit or RF24_CRC_16 for 16-bit Cyclic Redundancy Check (Error checking)
Serial.begin(115200);
//radio.printDetails(); // Print detailed radio configuration
pinMode(ledPin, OUTPUT);
}
void loop() {
received_then_sent();
delay(10);
}
void received_then_sent() {
network.update();
// Receiving //
//Serial.println("before available");
if(network.available() ) {
//Serial.println("before read");
digitalWrite(ledPin, HIGH);
network.update();
RF24NetworkHeader header;
network.read(header, &received_msg, sizeof(received_msg) );
//Serial.println("after read");
delay(10);
// Multicast the received message to the child nodes
for (int i = 0; i < 5; i++) {
RF24NetworkHeader child_header(child_nodes[i]);
bool ok1 = network.write(child_header, &received_msg, sizeof(received_msg));
delay(10);
//String sent_to = String(child_nodes[i]);
if (ok1) {
Serial.print("Sent to node: ");
Serial.print(child_nodes[i]);
Serial.print(": ");
Serial.println(received_msg);
} else {
Serial.print("Failed to send to node: ");
Serial.println(child_nodes[i]);
}
}
// Process the received data in a structured manner
String receivedData = String(received_msg);
int delimiterIndex = receivedData.indexOf('$'); //The indexOf() function returns the position of the first occurrence of '$' within the String. If the character '$' is not found, it returns -1.
if(delimiterIndex != -1) {
String parsedData = receivedData.substring(0, delimiterIndex); // Extract the part before '$'
//Serial.println(" inside delimiter loop ");
// Split the parsed data using the '-' delimiter
int hyphenIndex = parsedData.indexOf('-');
String code = parsedData.substring(0, hyphenIndex); // extracts the "code" from the whole received String
parsedData.remove(0, hyphenIndex + 1); // Remove the part before the first hyphen
hyphenIndex = parsedData.indexOf('-'); // Split the parsed data using the '-' delimiter
String from_node_str = parsedData.substring(0, hyphenIndex);
uint16_t from_node = from_node_str.toInt(); //Converts the 'to_node_str' String into an unsigned integer (uint16_t) value
parsedData.remove(0, hyphenIndex + 1); // Remove the part before the second hyphen
hyphenIndex = parsedData.indexOf('-'); // Split the parsed data using the '-' delimiter
String command = parsedData.substring(0, hyphenIndex);
parsedData.remove(0, hyphenIndex + 1); // Remove the part before the third hyphen
String message = parsedData;
// Now 'code', 'from_node', 'command', 'message' variables contain the parsed values
// You can use these variables as needed
Serial.print(this_node);
Serial.print(" ");
Serial.print("Received from node: ");
Serial.print(from_node);
Serial.print(" | code: ");
Serial.print(code);
Serial.print(" | with command: ");
Serial.print(command);
Serial.print(" | and message: ");
Serial.println(message);
if(code == "xYaZ") {
int r_delay = random(0,6000);
delay(r_delay);
Serial.println(r_delay);
if(command == "rollcall") {
sendData();
}
}
}
lastTransmissionTime = millis();
}
// Check for timeout to clear the buffer
currentTime = millis();
if(currentTime - lastTransmissionTime > transmissionTimeout) {
//Serial.println("Connection Lost!!");
digitalWrite(ledPin, LOW);
}
}
void sendData() {
network.update();
RF24NetworkHeader header2(master_node);
bool ok = network.write(header2, &gaveData[0], gaveData.length() );
if(ok) {
Serial.print("Done!! ");
Serial.println(gaveData);
//Serial.print(" ");
//Serial.println( gaveData.length() ); // Print the size of the transmitted message
}
else{
Serial.println("Failed!!!");
bool ok = network.write(header2, &gaveData[0], gaveData.length() );
}
}```