Concatenating multiple float variables with limiter to char array

I have multiple sensor outputs from different libs, e.g. date/time form time lib, humidity from DHTxx lib, temperature from DS18B20 lib, weight from the ADS1231 lib. I think all variables are float.

I like to transfer this variables with a single payload over the RFM69 lib http://lowpowerlab.com/blog/2013/06/20/rfm69-library/ values should be comma separated. The radio lib expects a char array as payload. So I have to

  • trim the library output to a decent number of decimal places
  • add a comma between the variables
  • concatenate all stuff

First I thought converting all float to a string and than lazy merge all with a "+" together is the way to go. But I found some advices and warnings to do this. The concerns go in the direction of not sufficient declared variables. I don't know is there a general problem or is it only about accurateness.

Second plan is to convert all float with dtostrf() to a char and then concatenate all with known length and so a single char array to send it via radio.

sprintf() is not working in the Arduino IDE so what's the best and most fault-tolerant (e.g. I could have negative values by sensor errors or higher values as normally expected) to handle this?

How do you concatenate chars? Have a long char and "insert" variables at the "right" position (so I have to be 100% sure about the number of digits a value has and also plus or minus) or to add each existing variable to the next, what means get the length of the current char array, get the length of the variable I like to add, expand the array, add the new var to the existing target array, do all stuff for the next var. Strings and + is more easy, but also more dangerous or memory wasting?

I don't know if it will suit your particular application but it's possible to handle floats to some extent in sprintf by getting creative with %d.%d.

Here's the basic idea:

#define sprintf_f(f,d) (int)f, (int)((f - (int)f) * 1 ## d)

char string[20];

float floatValue = 123.45678;

void setup()
{
  Serial.begin(9600);
  sprintf(string, "%d.%03d", sprintf_f(floatValue,000));
  Serial.println(string);
}

void loop(){}

Just make sure the number of zeros in the 2nd argument to the macro matches the number in the 2nd %0?d format.

why would you start off converting all float to string and then lazy merge makes no sense

If you look in the RFM69 library examples, there is a Struct_send and Struct_receive. Use that template to send and reconstruct the data as bytes without converting to character strings.

Problem with Struct is that I have to know on the gateway side the structure of the sent data. I can not count on this because multiple nodes can have different data sets, one can have only temperature an other can have multiple temperature sensors and a DHT sensor. The gateway should only collect data independently from the sensors I will have on the node side. I think so it makes no sense to use a Struct approach. I will also add new nodes with at the moment unknown sensors in a running environment without updating the gateway. So Struct is not the way to go or do I see oversee or misunderstand something?

Are all the data sets from the nodes arrays of floats with different numbers of elements? I’m not familiar with RFM69, but there has to be a way to send and receive the data as bytes.

On the other hand, if you use dtostrf to generate character strings I don’t see why they could not be concatenated with something like this

void setup() {

  Serial.begin(9600);

  char sensor1[6]; //should handle xxx.x and null terminator
  char sensor2[7]; //should handle xxx.xx and null terminator
  float x = 123.456;
  float y = 456.789;

  dtostrf(x, 5, 1, sensor1);
  dtostrf(y, 6, 2, sensor2);

  char buffer[strlen(sensor1) + strlen(sensor2) + 1];

  sprintf(buffer, "%s,%s", sensor1, sensor2);

  Serial.println(buffer);
}

void loop() {
}

Thanks for this example, so it is for me clearer now how width on dtostrf and char length work together.

I thought about sprintf also but it is not working in the Arduino environment.

I found this example from Rob http://forum.arduino.cc/index.php?topic=103935.msg779555#msg779555 but I don’t like it really much because you have to insert things on the right position and things are not error tolerant, e.g. in case I add an additional digit or a minus sign appears. So I’m searching for a bit more robust solution.

Clemens: I thought about sprintf also but it is not working in the Arduino environment.

I take it post #1 was of no use to you then?

Sorry, I was wrong! sprintf is only not working with float. So fine! It is working as in the example explained, I'll use this, many thanks!

How to enable floats in sprintf/sscanf