Central node, how to store and retrieve data from other nodes?

I am looking to set up a central node in a network of sensors. The sensors report by radio, some are mobile and move around, some are stationary. Most are already working.

I would like the central node to listen and store the last value it received from all the other sensors. Then when I get close enough to it with my mobile unit I call the central node and it will tell me what I want to know about a given sensor.

I am working with the radiohead library and this is what I have to work with for each message.

  uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];
  uint8_t len = sizeof(buf);
  uint8_t from;
  uint8_t to;
  uint8_t id;
  uint8_t flags;
  if (manager.recvfromAck(buf, &len, &from, &to, &id, &flags))

I would like to store:

the first two bytes of the message(though most are a single byte)
The from byte,
and the flags byte

That is 4 bytes. What is the best way to go about this?

In memory is likely easiest, just stumped how to set it up. Guessing some kind of an array, but having a hard time visualizing how that would work.

An array to store the last 10 messages from any station I can see, but in my case not all stations report at the same frequency and the one I may be interested in could be message 50. which would not work with limited memory.

epromm is likely better, again not seeing how to do the actual store and retrieval of the 4 different bytes, sorted by a particular one.

While I mention epromm I would also be happy going an sd card route and logging everything.(I have done that and sort of know my way around it), but again how to go about retrieving the data for a give node.

Total number of nodes is around 12, but subject to change. Ideally I would like to make it flexible about new nodes being added or removed, vs hard coded for each node.

To sum up any thoughts on how to go about storing and retrieving the last data point for a given node?

Thanks,
Brandan

Create a struct that holds the data for a single message and then create an array of the structs.

If this is to be a long running project an SD Card would probably be better as it can withstand more write cycles.

...R

I was guessing a struct would be part of the answer. I have limited experience with them. I can see how they could be used to keep track of the last x messages. Not so sure how to access and keep track of them when what I am sorting by is one of the data elements.

The struct would look something like this I believe.

struct station_report {
  uint8_t from;
  uint8_t buf[2];
  uint8_t flags;
} station [20];

If I was going to keep a log of message I would be trying something like this.

//int current; //global var to keep track of where I am in array as I have not found a handy bump array command.

if (manager.recvfromAck(buf, &len, &from, &to, &id, &flags)){
station[current].from=from;
station[current].buf=buf;
station[current].flags=flags;
current++;
if (current>19){current=0;}
}

How would a person go about it when instead of keeping track of the last 20 messages I instead want each station to overwrite its last report in the struct?

Then how does a person get the report for station 100? I would like to think there is a cleaver version of the next line, but no idea what it would look like.

station[?].from==100

Hard coding it for each station I could figure out. Much rather not hard code it though as the reporting stations are subject to change and it is going to be a pain to directly access this node just to recode it adding a new station.

Side note:While I am only interested in 12 or so stations, their numbering ranges over most of the span from 1-254.

(good point for using a memory card for long running programs )

Edited: an obvious error in my sydo-code.

I think it would help my understanding of the problem if you were to write an english (not code) description of the way you want the system to work. At the moment I think there is too much focus on the implementation details and it may help to look beyond that.

...R

I have radio nodes that report temperature of several buildings, the water levels in irrigation ditches(over several miles worth of ditches), a few irrigation pumps now have nodes that will turn them off. Also several alarm related nodes to report if the ditches have over flowed.

What I am after is a central radio that receives all of those other radios nodes. Some of the other nodes it ignores(the central node does not need to do anything with the temperature ones) Some of the water alarm nodes are out of range of the base stations and it relays those as it gets them.

Both of the above I have implemented and I have base stations in a few places where I can view the last reading from all of the nodes and one that writes them to an SD card with the time.

I am now starting to work on a mobile node that goes in a vehicle with me. Most of the time it will be out of range of some or even all of the other nodes and the central radio. (While I call it a central radio, it is actually on top of a hill a few miles away, not very handy to change if I need to update the code very often.) Not very central but excellent coverage of the area I am interested in. When I do come in range of the central node I want to be able to check the water levels in particular ditches without waiting for them all to report.

Depending on how the ditches are set I may be interested in different nodes.

On one day I may like to ask the central node what level are the ditches at node 14, 24 and 34. A different day those ditches may be turned off and I instead want to know about node 40 and 50. Also want a way to check if any of the overflow alarms have gone off. If so once I am notified about the alarm node have a way to clear the alarm status.

Side note: Why I am interested in the flags. Currently I have it set up so that a given node will set different flags in the message it sends to tell the central node if it needs to forward the message, and what type of message it contains which is needed for the receiving station to know how to display the info. That makes it so I can add more stations at will without having to recode the central node or the base stations each time I add something.

Although most Instructables are terrible, this one describes a reasonable attempt at an Arduino wireless mesh network, that collects data from many nodes.

I spent a couple of hours eliminating all the nasty Strings, as it is hard to imagine how the original version could have worked for very long. Let me know if you are interested in it.

If you care to share I would be interested, it is an interesting idea he has there. I have issues with parts of it mostly with regard to power use and remote battery operated sensors, but I can see places where that could be very handy and the power needs would not be an issue. I particularly like how he gets things agreeing on a common time.

As for my own problem. I think I figured out what I was missing. Turns out the part that really had me stumped was how to find if a station was already in the array. If anyone has thoughts on how to do this better I would be interested. That said it is working and I should not need to edit any part of it when I add more stations. If I ever remove a lot of stations in real life, I see how I can clear the array simply and remotely. Very happy.

  if (manager.recvfromAck(buf, &len, &from, &to, &id, &flags))
  {
    for (int i = 0; i < 19; i++) {
      if (station[i].from == from or station[i].from == 0  ) {
        station[i].from = from;
        station[i].buf[0] = buf[0];
        station[i].buf[1] = buf[1];
        station[i].flags = flags;
        break;
      }
    }//For
//print out what we have for testing reasons.
for(int i = 0; i < 19; i++)
{
  Serial.print(station[i].from);  Serial.print(", ");  Serial.println((char*)station[i].buf);
}

Yes, the wireless mesh code works quite well. I implemented it with just two nodes and checked it out pretty thoroughly. It is fun to watch numbers propagate through the network!

I have not tried a larger number of nodes yet, but that is in the works. 256 nodes is now the maximum, but the timeslot width (now 4096 ms) will need to be increased for > 16 nodes.

My "no Strings" version is attached (too long to post inline). It should function identically, with one exception: network time propagates from a lower to a higher node number, rather than ONLY from node 0 as in the original. My reasoning was that node 0 is not always visible to other nodes.

Also, I took out all the base station print routines, as those were clearly implementation specific and not necessary for basic network operation.

Finally for safety and sanity checks, I recommend to replace all calls to sprintf() with snprintf() (also on my todo list).

APC220Mesh_JR5.ino (12.1 KB)

Just noticed this thread here about the nodes. Thanks Jrem. I'll definitely check that one out. No strings attached is good!

As I understand you have 20 stations, and only want to keep the latest report of each station.

Then use the station ID as your array index - works easiest if your stations are numbered 0 through 19, then you can get rid of the .from part of your struct as that's the same as the array index. Saves a byte per struct of memory; makes your code a bit easier as you don't have to start iterating through the array to find the correct station.

The snippet from #6 would then become:

  if (manager.recvfromAck(buf, &len, &from, &to, &id, &flags))
    station[from].buf[0] = buf[0];
    station[from].buf[1] = buf[1];
    station[from].flags = flags;

    //print out what we have for testing reasons.
    for(int i = 0; i < 19; i++)
    {
      Serial.print(i);
      Serial.print(", ");
      Serial.println((char*)station[i].buf);
    }
  }

Brandan34:
Depending on how the ditches are set I may be interested in different nodes.

On one day I may like to ask the central node what level are the ditches at node 14, 24 and 34. A different day those ditches may be turned off and I instead want to know about node 40 and 50. Also want a way to check if any of the overflow alarms have gone off. If so once I am notified about the alarm node have a way to clear the alarm status.

That seems a very sensible concept. If I was faced with that problem I would use a RaspberryPi for the central node (either on its own or in company with the central Arduino). IMHO it is very much easier to do serious data processing on an RPi and you could fairly easily build a webserver that you can access from a smartphone or laptop whenever you are within range.

...R

Then use the station ID as your array index - works easiest if your stations are numbered 0 through 19,


Ahh not sure why I did not think of that. Well because I was clueless how to do this :slight_smile:

I will be building two more independent networks of these in coming weeks and I will take you up on your idea and code, that makes it a lot simpler than having to look through the array. Simple and faster saves batteries, which is all to the good :smiley:

Very tempting to retro fit the current array of sensors when I change their batteries next. I would have to change station numbers, but very doable as I have misc other updates to do at the same time.


I have looked at pies, but never messed with one. My impression is they use quite a bit more power and have a pretty long start up time is that correct?

With the power draw in mind I have not given them much thought for battery operation, should I give them another look?

jremington:
My "no Strings" version is attached (too long to post inline). It should function identically, with one exception: network time propagates from a lower to a higher node number, rather than ONLY from node 0 as in the original. My reasoning was that node 0 is not always visible to other nodes.

Thanks for sharing, very nice job cleaning up the code, much shorter and cleaner for a basic place to start building from. I have it saved off to the side and may have a use for it here soon.

I am surprised the original did not have the code you are talking about for the timing. How you describe it is how the article also described it should work.(I admit that I did not read more than half of the original ino and did not notice if or how it did that part of the timing.)