How to split a long string

Hi. I am trying to make a weather station. For the outside temperature i am trying to get some info from an API. I have the past working where it returns all of the data on the web page as a string. The microcontroller im using is a NodeMCU.

The site i am using is the following:
http://weerlive.nl/api/json-10min.php?locatie=amsterdam

The string it creates now is exactly the same as what gets displays on that page.

My question is: How do i split/process this string to only get the part that says the temperature: "temp": "-4.2"

How do i read the string starting from "temp": up until the next comma?

Please read and follow the instructions in the "How to use this forum" post.

Use of String objects is not advised in Arduino, as they cause memory problems. What you want to do is straightforward using character arrays (C-strings).

There are delimiters in the output that the link generates. You can look for the first '[', and start storing data when it arrives. Store enough characters until you are sure to have the value of interest. Add a NULL after each character is stored in the char array.

Then, use strtok() and a while loop to parse the string, using ',' as the delimiter. If the token contains (strstr()) "temp", you've found the correct token.

Parse the token using ':' as the delimiter. The last token will be the value you want, with the quotes around it.

Change the double quotes to spaces, and use atof() to convert the token to a float, if you need it as a float.

jremington:
Please read and follow the instructions in the "How to use this forum" post.

Use of String objects is not advised in Arduino, as they cause memory problems. What you want to do is straightforward using character arrays (C-strings).

Can i just replace the String declaration with char[] or would i have to change more of the code? Here is the code snipped that gets the data: (variable info is declared as a string)

HTTPClient http; //Declare an object of class HTTPClient
    http.begin(API_URL); //Specify request destination
    int httpCode = http.GET(); //Send the request
    if (httpCode > 0) { //Check the returning code
      info = http.getString(); //Get the request response payload
    }
    http.end(); //Close connection

I would also prefer a char array because i have more experience working with those.

PaulS:
There are delimiters in the output that the link generates. You can look for the first '[', and start storing data when it arrives. Store enough characters until you are sure to have the value of interest. Add a NULL after each character is stored in the char array.

Then, use strtok() and a while loop to parse the string, using ',' as the delimiter. If the token contains (strstr()) "temp", you've found the correct token.

Parse the token using ':' as the delimiter. The last token will be the value you want, with the quotes around it.

Change the double quotes to spaces, and use atof() to convert the token to a float, if you need it as a float.

Nice thanks. I haven't worked a lot with strings but i will see if i can get it to work.

Is info defined as String?

Is there a version of "http.getString()" or a similar function that returns a character array?

Yes, info is a String. I don't think there is a http.getString() version for an array but I could convert it to an array with something like a for-loop and string.charAt(i). Might have to try that if I can't get delimiters to work.

The problem with that approach is that you are constantly creating/destroying String objects, which leads to the memory problems and lockups that so many people have experienced.

You might look for another library that uses character arrays.

HTTPClient is a Stream, so the typical Serial Input Basics example can be used to watch for the substring "of interest".

Just call http.available() and http.read(), instead of Serial.available() and Serial.read().

-dev:
HTTPClient is a Stream, so the typical Serial Input Basics example can be used to watch for the substring "of interest".

Just call http.available() and http.read(), instead of Serial.available() and Serial.read().

Don't think so. Now i get an error:

class HTTPClient' has no member named 'available'

Don't think so. Now i get an error:
class HTTPClient' has no member named 'available'

My mistake... I think this is part of the "Bridge" system. GACK. Very String-class oriented. The readString method is part of the original Stream class, so I though HTTPClient was derived from it.

You could either:

  • use the String class functions to search for "temp", then look for the next quoted value string. Parse the value string as a float. This is the least efficient, and the most susceptible to a variety of String dangers.

  • use a JSON library to parse the info.c_str(). Then access the resulting structure. This is the most complicated, but it might be worth it if you access a lot of the JSON data.

  • use C string functions to scan the info.c_str(). This is most efficient.

Personally, I would use the last approach. This is what PaulS was suggesting, with the exception that the info can only be obtained as a String. You can use the C string (char array) functions on the info.c_str() array:

const char JSON[] = R"jsonString(
{ "liveweer": [{"plaats": "Amsterdam", "temp": "7.3", "gtemp": "5.3", "samenv": "Geheel bewolkt", "lv": "99", "windr": "West", "windms": "3", "winds": "2", "windk": "5.8", "windkmh": "10.8", "luchtd": "1032.8", "ldmmhg": "775", "dauwp": "7", "zicht": "2", "verw": "Bewolkt en nevelig of mistig met plaatselijk (mot)regen.", "sup": "08:45", "sunder": "16:31", "image": "bewolkt", "d0weer": "bewolkt", "d0tmax": "9", "d0tmin": "6", "d0windk": "2", "d0windknp": "4", "d0windms": "2", "d0windkmh": "7", "d0windr": "267", "d0neerslag": "13", "d0zon": "0", "d1weer": "halfbewolkt", "d1tmax": "9", "d1tmin": "7", "d1windk": "2", "d1windknp": "", "d1windms": "", "d1windkmh": "", "d1windr": "W", "d1neerslag": "60", "d1zon": "10", "d2weer": "halfbewolkt", "d2tmax": "8", "d2tmin": "5", "d2windk": "3", "d2windknp": "", "d2windms": "", "d2windkmh": "", "d2windr": "W", "d2neerslag": "40", "d2zon": "10", "alarm": "0"}]}
)jsonString";

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

  String info( JSON );
  Serial.println( info.c_str() );

    const char  TEMP_NAME[] = "\"temp\""; // note embedded double quotes

    // Use the strstr functuon to look for the key
    char *tempPtr     = strstr( info.c_str(), TEMP_NAME );

    // If the name was found, get the value
    if (tempPtr != nullptr) {

      // Use the strchr function to look for the colon
      char *valuePtr = strchr( tempPtr, ':' );

      if (valuePtr != nullptr) {
        valuePtr++; // step over the colon
        valuePtr = strchr( valuePtr, '\"' ); // look for the starting double quote

        if (valuePtr != nullptr) {
          valuePtr++; // step over the starting double quote
          
          // Use the atof function parse a float value from 
          //   what follows (stops at the ending double quote).
          float value = atof( valuePtr );

          Serial.println( value );
        } else {
          Serial.println( "no value \"" );
        }
      } else {
        Serial.println( "no :" );
      }
    } else {
      Serial.print( "no " );
      Serial.println( TEMP_NAME );
    }
}

void loop() {}