Sorting for Correct Message

Hello,

I am currently making an RF24Network with tmrh20’s library. I have three grandchild nodes sending values to one child node which stores those values, takes its own reading, and sends all of the values to the master node. When I start it up and look at the serial monitor on the master node, it always picks up the values from the child node, but all the grandchildren are inconsistently picked up. My main suspect is a lack of proper sorting from the child node. Here is my code:

#include <SPI.h>
#include "RF24.h"
#include "RF24Network.h"
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 2

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

RF24 radio (7, 8);
RF24Network network(radio);

const uint16_t node01 = 01;
const uint16_t node00 = 00;
const uint16_t node011 = 011;
const uint16_t node021 = 021;
const uint16_t node031 = 031;

const unsigned long interval = 2000;
unsigned long last_got;

int m11;
int t11;
int id011;
int m21;
int t21;
int id021;
int m31;
int t31;
int id031;

struct payload_01 {
  float moisture01;
  float temp01;
  int m011;
  int t011;
  int m021;
  int t021;
  int m031;
  int t031;
  int id01;
};

struct payload_011 {
  float moisture011;
  float temp011;
  int id011;
};

struct payload_021 {
  float moisture021;
  float temp021;
  int id021;
};

struct payload_031 {
  float moisture031;
  float temp031;
  int id031;
};



void setup()
{
  Serial.begin(9600);
  delay(1000);
  radio.begin();
  SPI.begin();
  sensors.begin();
  network.begin(01);
  delay(1000);
}

void loop()
{
  network.update();
  unsigned long now = millis();
  RF24NetworkHeader header011;
  network.peek(header011);
  payload_011 payload011;
  network.read(header011, &payload011, sizeof(payload011));
  id011 = payload011.id011;
  if (id011 == 11)
  { m11 = payload011.moisture011;
    t11 = payload011.temp011;
    payload011.id011 = 0;
  }

  RF24NetworkHeader header021;
  network.peek(header021);
  payload_021 payload021;
  network.read(header021, &payload021, sizeof(payload021));
  id021 = payload021.id021;
  if (id021 == 21)
  { m21 = payload021.moisture021;
    t21 = payload021.temp021;
    payload021.id021 = 0;
  }

  RF24NetworkHeader header031;
  network.peek(header031);
  payload_031 payload031;
  network.read(header031, &payload031, sizeof(payload031));
  id031 = payload031.id031;
  if (id031 == 31)
  { m31 = payload031.moisture031;
    t31 = payload031.temp031;
    payload031.id031 = 0;
  }

  delay(100);
  payload_01 payload01;
  if (now - last_got >= interval)
  { sensors.requestTemperatures();
    payload01.moisture01 = analogRead(A0);
    payload01.temp01 = sensors.getTempFByIndex(0);
    payload01.m011 = m11;
    payload01.t011 = t11;
    payload01.m021 = m21;
    payload01.t021 = t21;
    payload01.m031 = m31;
    payload01.t031 = t31;
    payload01.id01 = 1;
    RF24NetworkHeader header01(node00);
    network.write(header01, &payload01, sizeof(payload01));
    payload01.m011 = 0;
    payload01.t011 = 0;
    m11 = 0;
    t11 = 0;
    m21 = 0;
    t21 = 0;
    m31 = 0;
    t31 = 0;
    last_got = now;
  }
}

It might not be the most efficient all-around code, but the original got the job done with one grandchild node, and I didn’t have a problem modifying it for 2 grandchildren (maybe just luck?). But now with adding a third one, it is starting to become inconsistent.

A couple solutions that I think might work but don’t know how to use them properly:

  • name all id’s and have an extra variable that reads the id and figures out which message it is from there
    -have each message send certain values at the end of the string that the child node can sort from
  • have each one with a different header type and peek which header type it is and sort from there

I think the header would work best, but the documentation on it is a little thin, so I don’t know if that’s what it can be used for. One other thing is the nodes will be a reasonable distance away from each other and the readings are time-sensitive, so I do not want the child node to send anything back to the grandchildren. Let me know what you think. Thanks in advance.

Three instances of the struct containing two floats and one int makes sense. Three identical structs with different member names, and one instance of each does not.

Meaningless names, like m011, do not tell us anything.

You REALLY need to learn about arrays.

Why not get each grandchild to include its own ID in its messages? It means the messages will be 1 byte longer but it seems like a reasonable price to pay.

I have not used the Network feature myself, I thought it needed to use IDs for each device - if so, why not use that data?

For my own use I just get my "master" to query each of my "slaves" in turn - which has the advantage that the master knows exactly who is replying.

...R

I would like to announce that both of your advice has helped me out greatly. What I did here was instead of naming them differently, I just gave them separate id’s so it would read a payload, find what the id of that payload is, and set the values based on what the payload is instead of trying to know what payload it is before reading it. I tested it through the serial monitor of the child node, and it worked perfectly. Here is the code I tested out:

#include <SPI.h>
#include "RF24.h"
#include "RF24Network.h"
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 2

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

RF24 radio (7, 8);
RF24Network network(radio);

const uint16_t node01 = 01;
const uint16_t node00 = 00;
const uint16_t node011 = 011;
const uint16_t node021 = 021;
const uint16_t node031 = 031;

const unsigned long interval = 2000;
unsigned long last_got;

int m11;
int t11;
int m21;
int t21;
int m31;
int t31;

struct payload_01 {
  float moisture01;
  float temp01;
  int m011;
  int t011;
  int m021;
  int t021;
  int m031;
  int t031;
  int id01;
};

struct payload_ {
  float moisture;
  float temp;
  int id;
};




void setup()
{
  Serial.begin(9600);
  delay(1000);
  radio.begin();
  SPI.begin();
  sensors.begin();
  network.begin(01);
  delay(1000);
}

void loop()
{
  network.update();
  unsigned long now = millis();

  RF24NetworkHeader header;
  network.peek(header);
  payload_ payload;
  network.read(header, &payload, sizeof(payload));
  if (payload.id == 11) {
    m11 = payload.moisture;
    t11 = payload.temp;
  }

  else if (payload.id == 21) {
    m21 = payload.moisture;
    t21 = payload.temp;
  }

  else if (payload.id == 31) {
    m31 = payload.moisture;
    t31 = payload.temp;
  }


  if (now - last_got >= interval)
  {
    payload_01 payload01;
    sensors.requestTemperatures();
    // payload01.moisture01 = analogRead(A0);
    //payload01.temp01 = sensors.getTempFByIndex(0);
    //payload01.m011 = m11;
    //payload01.t011 = t11;
    //payload01.m021 = m21;
    //payload01.t021 = t21;
    //payload01.m031 = m31;
    //payload01.t031 = t31;
    //payload01.id01 = 1;
    // RF24NetworkHeader header01(node00);
    // network.write(header01,&payload01,sizeof(payload01));
    Serial.print(analogRead(A0));
    Serial.print(",");
    Serial.print(m11);
    Serial.print(",");
    Serial.print(m21);
    Serial.print(",");
    Serial.println(m31);
    payload01.m011 = 0;
    payload01.t011 = 0;
    m11 = 0;
    t11 = 0;
    m21 = 0;
    t21 = 0;
    m31 = 0;
    t31 = 0;
    last_got = now;
  }
}

Of course, I edited the grandchildren to match what this has. I could probably make arrays instead of copying things so many times, but as of now the memory is not a problem. I will look at how to properly work arrays in the near future, though.

The names like m011 are kind of clunky but are probably temporary. They are values from the grandchild nodes that I keep stored as integers in the child node to send to the master node. m is for moisture and t is for temperature, and the numbers on the end indicate which node that value came from. So m011 is the moisture reading from node 011, the first child of node 01.

What do you guys think about this code?