Get data from String

I have a String with 4 different data (temperature, humidity, pressure, luminous intensity). The data may vary:

 String data = "23.5#88#1002#12500#";

or

String data = "2.0#55#990#0#";

My problem is: how to get that 4 date to singles variables:
temperature = 23.5
humidity = 88
pressure = 1002
luminous = 12500

If you really must use Strings (why ?), then this should give you some ideas

  String temp = data.substring(0, data.indexOf("#"));

It is not a good idea to use the String (capital S) class on an Arduino as it can cause memory corruption in the small memory on an Arduino. This can happen after the program has been running perfectly for some time. Just use cstrings - char arrays terminated with '\0' (NULL).

The parse example in Serial Input Basics illustrates how numbers can be extracted from cstrings.

...R

long tempInt, tempDec, humidity, pressure, luminosity;
sscanf(data.c_str(), “%d.%d#%d#%d#%d#”, &tempInt, &tempDec, &humidity, &pressure, &luminosity);

note you get the integral and decimal part of the t° in two variables because on basic arduino the %f format for float is not implemented

You could do an float temperature = atof(data.c_str()); if you want it directly as a float or use the String class method toFloat()``float temperature = data.toFloat();as your temperature is the first data in the String

But as mentioned, we would discourage building such String in favor of cStrings

@J-M-L:

Thank you.
That's exactly what I needed.

sly_0:
@J-M-L:

Thank you.
That's exactly what I needed.

No really what you need is moving away from the String class... but short term that can be a temporary workaround ;D ;D :grin: :grin:

@OP

If it happens that you are receiving the indicated message via UART Port, then the following strategy could be a solution:

Sender Sketch:(transmitting "23.5#88#1002#12500#")

#include<SoftwareSerial.h>
SoftwareSerial SUART(2, 3);

char myData[] = "23.5#88#1002#12500#";
void setup()
{
  Serial.begin(9600);
  SUART.begin(9600);
}

void loop()
{
  Serial.println(myData);
  SUART.println(myData);
  delay(1000);
}

Receiver Sketch:

#include<SoftwareSerial.h>
SoftwareSerial SUART(2, 3);
int i = 0;
char myData[4][20] = {0};

void setup()
{
  Serial.begin(9600);
  SUART.begin(9600);
}

void loop()
{
  byte n = SUART.available();
  if (n != 0)
  {
    SUART.readBytesUntil('#', myData[i], 20);
    i++;
    if (i == 4)
    {
      float x1 = atof(myData[0]);
      Serial.println(x1, 1);
      //------------------------
      int x2 = atoi(myData[1]);
      Serial.println(x2);
      //-------------------------
      int x3 = atoi(myData[2]);
      Serial.println(x3);
      //-------------------------
      int x4 = atoi(myData[3]);
      Serial.println(x4);
      //-------------------------
      Serial.println("=======================");
      while(1);
    }
  }
}

Receiver Screenshot
smn.png

smn.png

GolamMostafa:
SUART.readBytesUntil('#', myData*, 20);*
[/quote]
careful - this "works" because you have large enough global buffers that have been initialized to 0 and so the atof() and atoi() functions will actually find a proper cString to work with in the buffer because you never fill them in completely.
Also if you were to send a second buffer to assess, as the code you have does not reset content nor add the trailing NULL char in the right place, you would end up possibly with garbage number : for example if the first time I send [color=red]23.5[/color]# for the temperature - the buffer will hold
* *'[color=red]2[/color]' '[color=red]3[/color]' '[color=red].[/color]' [color=red]5[/color]' 0 0 0 0 0 ...* *
if the second time you send [color=blue]23[/color]# the readBytesUntil() will do it's job and the buffer will hold again
* *'[color=blue]2[/color]' '[color=blue]3[/color]' '[color=red].[/color]' [color=red]5[/color]' 0 0 0 0 0 ...* *
leading to the wrong conversion.
The right approach is described in Serial Input Basics

'#' is skipped, array is pre-filled with 0s; there is an in situ NULL byte; as a result, the conversion correctly takes place. The receiver sketch is tested only for one 'reception frame'. If the OP changes his message format, the codes have to be changed accordingly.

I have noted down your comments.

indeed - might have been obvious for you but the dependency on having a trailing ‘\0’ in the array because the length of a number between the # is likely shorter than 19 is an important piece of hidden information, as much as the fact the arrays need to be cleared before each ‘run’

Due to the risk of de-sync if multiple scans are needed (not handled either above) in case of a malformed Input the best approach to recommend to the OP (in case of a Stream) is the technic described in the Serial Input tutorial pointed above (which brings OP back to her/his original question, parsing the cString)

That being said, your post was good to show things can also be scanned as they come in

if you don’t want to build any protection measure you could avoid the buffer and use

t = Stream.parseFloat(); // the t°
Stream.read(); // skip the #
h = Stream.parseInt(); // the humidity
Stream.read(); // skip the #
p = Stream.parseInt(); // the pressure, 
Stream.read(); // skip the #
l = Stream.parseInt(); // the luminosity
Stream.read(); // skip the #

(untested but if I remember correctly the first offending byte is left in the Stream after reading the number and initial spaces are skipped)

J-M-L:

long tempInt, tempDec, humidity, pressure, luminosity;

sscanf(data.c_str(), “%d.%d#%d#%d#%d#”, &tempInt, &tempDec, &humidity, &pressure, &luminosity);



note you get the integral and decimal part of the t° in two variables because on basic arduino the %f format for float is not implemented

Won’t the values 2.5 and 2.05, for example, give the same results?
That’s a worry.

TheMemberFormerlyKnownAsAWOL:
Won't the values 2.5 and 2.05, for example, give the same results?
That's a worry.

very fair point - it’s a more than a worry, it’s a fail! My bad

J-M-L:
(untested but if I remember correctly the first offending byte is left in the Stream after reading the number and initial spaces are skipped)

Your codes of Post#9 are working well.
Receiver Sketch: (continuous reception, parsing, and display)

#include<SoftwareSerial.h>
SoftwareSerial SUART(2, 3);

void setup()
{
  Serial.begin(9600);
  SUART.begin(9600);
}

void loop()
{
  byte n = SUART.available();  //getting from FIFO Buffer
  if (n != 0)
  {
    float t = SUART.parseFloat(); // the t°
    Serial.print("Temp: "); Serial.println(t);
    //---------------------------------------
    SUART.read(); // skip the #
    int h = SUART.parseInt(); // the humidity
    Serial.print("Humidity: "); Serial.println(h);
    //----------------------------------------
    SUART.read(); // skip the #
    int p = SUART.parseInt(); // the pressure,
    Serial.print("Pressure: "); Serial.println(p);
    //---------------------------------------
    SUART.read(); // skip the #
    int l = SUART.parseInt(); // the luminosity
    Serial.print("Luminosity: "); Serial.println(l);
    //----------------------------------------
    Serial.println("=============================");
  }
}

Screenshot:
smFl.png

smFl.png