ESP8266 parsing +IPD response from serial using Arduino UNO/Nano software serial

Hello!

I am using an ESP8266 with arduino uno/nano to send data to a mysql server, using AT commands and software serial, with no problem at all. Everything works fine.

Now, I want to be able also to extract data from the server response.
The only problem is, that I can't write a code to actually parse this serial response, and extract from there, the data I am interested. It is difficult to do this?

Here is the code:

#include <SoftwareSerial.h>

const byte rxPin = 2;
const byte txPin = 3;

String AP = "xxxxxxx";       // CHANGE ME
String PASS = "xxxxx"; // CHANGE ME
String HOST = "home.adrianc.ro";
String PORT = "80";
int countTrueCommand;
int countTimeCommand; 
boolean found = false; 

SoftwareSerial ESP8266 (rxPin, txPin);

unsigned long lastTimeMillis = 0;

void setup() {
  Serial.begin(9600);   
  ESP8266.begin(9600);
         sendCommand("AT",5,"OK");
         sendCommand("AT+CWMODE=1",5,"OK");
         sendCommand("AT+CWJAP=\""+ AP +"\",\""+ PASS +"\"",20,"OK");
  delay(1000);
}

void printResponse() {
  while (ESP8266.available()) {
    Serial.println(ESP8266.readStringUntil('\n')); 
  }
}

void loop() {

  if (millis() - lastTimeMillis > 30000) {
    lastTimeMillis = millis();

    ESP8266.println("AT+CIPMUX=1");
    delay(1000);
    printResponse();

    ESP8266.println("AT+CIPSTART=4,\"TCP\",\"home.adrianc.ro\",80");
    delay(1000);
    printResponse();

    String cmd = "GET /weatherstation/readtemp.php?";
    ESP8266.println("AT+CIPSEND=4," + String(cmd.length() + 4));
    delay(1000);

    ESP8266.println(cmd);
    delay(1000);
    ESP8266.println(""); 
  }

  if (ESP8266.available()) {
    Serial.write(ESP8266.read());
  }

}

void sendCommand(String command, int maxTime, char readReplay[]) {
  Serial.print(countTrueCommand);
  Serial.print(". at command => ");
  Serial.print(command);
  Serial.print(" ");
  while(countTimeCommand < (maxTime*1))
  {
    ESP8266.println(command);//at+cipsend
    if(ESP8266.find(readReplay))//ok
    {
      found = true;
      break;
    }
 
    countTimeCommand++;
  }
 
  if(found == true)
  {
    Serial.println("OYI");
    countTrueCommand++;
    countTimeCommand = 0;
  }
 
  if(found == false)
  {
    Serial.println("Fail");
    countTrueCommand = 0;
    countTimeCommand = 0;
  }
 
  found = false;
 }

The response from server is:

09:20:35.183 -> AT+CIPMUX=1
09:20:35.183 -> 
09:20:35.183 -> OK
09:20:36.214 -> AT+CIPSTART=4,"TCP","home.adrianc.ro",80
09:20:36.261 -> 4,CONNECT
09:20:36.308 -> 
09:20:36.308 -> OK
09:20:38.288 -> AT+CIPSEND=4,37
09:20:38.288 -> 
09:20:38.322 -> OK
09:20:38.322 -> > 
09:20:38.322 -> Recv 37 bytes
09:20:38.322 -> 
09:20:38.322 -> SEND OK
09:20:38.459 -> 
09:20:38.459 -> +IPD,4,8:
09:20:38.459 -> 5.00
09:20:38.459 -> 4,CLOSED

So, the part that I am interested in, is 5.00, right after: "+IPD,4,8:" and before "4,CLOSED" wich is the server response. how can I parse that, and transform it to a string / and eventually to a float / or int.

If I must put some delimiter, special character or something, for the parsing process to be easier, before and after 5.00, I can do this with no problem.

Thank you very much!
Adrian.

You only need to modify

void printResponse() {
  while (ESP8266.available()) {
    Serial.println(ESP8266.readStringUntil('\n')); // i would actually use Serial.print() here
  }
}

in such a way that you first store the response before printing say

void printResponse() {
  String s="";
  while (ESP8266.available()) {
    s+=ESP8266.readStringUntil('\n');
  }
  Serial.print(s);
  // now here you can parse and look for "+IPD" look for another line ending (if there is) and then extract the numeric value. 
}

Juraj:
WiFiEspAT/src/utility/EspAtDrv.cpp at master · JAndrassy/WiFiEspAT · GitHub

I tried in the past with WifiEspAT library, and even now, but with the same result... iit doesen't want to communicate with the module. Maybe if you have a working example, and would like to share???

Thank you!

Deva_Rishi:
You only need to modify

void printResponse() {

while (ESP8266.available()) {
   Serial.println(ESP8266.readStringUntil('\n')); // i would actually use Serial.print() here
 }
}



in such a way that you first store the response before printing say


void printResponse() {
 String s="";
 while (ESP8266.available()) {
   s+=ESP8266.readStringUntil('\n');
 }
 Serial.print(s);
 // now here you can parse and look for "+IPD" look for another line ending (if there is) and then extract the numeric value.
}

Okey, I will try this, but once I have the string... I still need to parse it. So, I will be stuck :slight_smile: Working with strings is hard for a begginer :slight_smile: You have some code lines for me?:slight_smile:

adiculiniute:
I tried in the past with WifiEspAT library, and even now, but with the same result... iit doesen't want to communicate with the module. Maybe if you have a working example, and would like to share???

Thank you!

this WiFiEspAT library was published in August this year and is only for AT firmware 1.7.x (SDK 3).

you asked how to parse so I pointed you to the parsing done in my library, not to the library

the library has documentation and examples in IDE if you install it with Library Manager

adiculiniute:
Okey, I will try this, but once I have the string... I still need to parse it. So, I will be stuck :slight_smile: Working with strings is hard for a begginer :slight_smile: You have some code lines for me?:slight_smile:

There are plenty of examples on Strings in the IDE, the basic principal of parsing is fairly simple, look for a character, extract what comes after until another character, and if required convert that to a different data type. In your case after the '+IPD' there is still the ':' (and possibly another line ending, i can't tell from your last output) and then the value that you want, which you will need to convert to a float ? well you may need to do that manually. Many people will say you may as well go straight for c-strings and learn how to parse with them, and there is good reasons for doing that. In that case have a look at Serial Input Basics
I personally am not a fan of using the AT-commands firmware, and suggest that you consider writing your own firmware for the ESP using the Arduino IDE In that way you can do all the wifi control from within the ESP and just extract and send the data that you need to the Arduino. This is of course another completely different path, with a learning curve, but much more flexible, and in my opinion the way to go.

adiculiniute:
It is difficult to do this?

Thank you very much!
Adrian.

No.
Here is how I receive Serial on an ESP32

void fReceiveSerial_LIDAR( void * parameters  )
{
  bool BeginSentence = false;
  sSerial.reserve ( StringBufferSize300 );
  char OneChar;
  for ( ;; )
  {
    EventBits_t xbit = xEventGroupWaitBits (eg, evtReceiveSerial_LIDAR, pdTRUE, pdTRUE, portMAX_DELAY);
    // vTaskDelayUntil( &xLastWakeTime, xFrequency );
    if ( LIDARSerial.available() >= 1 )
    {
      while ( LIDARSerial.available() )
      {
        OneChar = LIDARSerial.read();
        if ( BeginSentence )
        {
          if ( OneChar == '>')
          {
            if ( xSemaphoreTake( sema_ParseLIDAR_ReceivedSerial, xSemaphoreTicksToWait10 ) == pdTRUE )
            {
              xQueueOverwrite( xQ_LIDAR_Display_INFO, ( void * ) &sSerial );
              xEventGroupSetBits( eg, evtParseLIDAR_ReceivedSerial );
              //
            }
            BeginSentence = false;
            break;
          }
          sSerial.concat ( OneChar );
        }
        else
        {
          if ( OneChar == '<' )
          {
            sSerial = ""; // clear string buffer
            BeginSentence = true; // found begining of sentence
          }
        }
      } //  while ( LIDARSerial.available() )
    } //if ( LIDARSerial.available() >= 1 )
    xSemaphoreGive( sema_ReceiveSerial_LIDAR );
    //            Serial.print( "fReceiveSerial_LIDAR " );
    //        Serial.print(uxTaskGetStackHighWaterMark( NULL ));
    //            Serial.println();
    //        Serial.flush();
  }
  vTaskDelete( NULL );
} //void fParseSerial( void * parameters  )

Here is how I parse the received Serial

void fParseLIDAR_ReceivedSerial ( void * parameters )
{
  // distribute received LIDAR info
  String sTmp = "";
  sTmp.reserve ( 20 );
  String sMessage = "";
  sMessage.reserve ( StringBufferSize300 );
  for ( ;; )
  {
    EventBits_t xbit = xEventGroupWaitBits (eg, evtParseLIDAR_ReceivedSerial, pdTRUE, pdTRUE, portMAX_DELAY) ;
    xQueueReceive ( xQ_LIDAR_Display_INFO, &sMessage, QueueReceiveDelayTime );
    //        Serial.println ( sMessage );
    int commaIndex = sMessage.indexOf(',');
    sTmp.concat ( sMessage.substring(0, commaIndex) );
    sMessage.remove( 0, (commaIndex + 1) ); // chop off begining of message
    //    Serial.println ( sTmp );
    if ( sTmp == "!" )
    {
      xSemaphoreGive ( sema_LIDAR_OK );
      //  Display info from LIDAR
      sLIDAR_Display_Info = sMessage;
    }
    if ( sTmp == "$" )
    {
      xEventGroupSetBits( eg1, evtResetWatchDogVariables );
    }
    if ( sTmp == "#")
    {
      // Serial.println ( "#" );
      xSemaphoreTake( sema_LIDAR_Alarm, xSemaphoreTicksToWait );
      sLIDAR_Alarm_info = sMessage;
      xSemaphoreGive( sema_LIDAR_Alarm );
      xEventGroupSetBits( eg, evtfLIDAR_Alarm );
    }
    //    Serial.println ( "parse serial ok" );
    sTmp = "";
    sMessage = "";
    xSemaphoreGive( sema_ParseLIDAR_ReceivedSerial );
    //    Serial.print( "fParseReceivedSerial " );
    //    Serial.print(uxTaskGetStackHighWaterMark( NULL ));
    //    Serial.println();
    //    Serial.flush();
  }
  vTaskDelete( NULL );
} // void fParseReceivedSerial ( void * parameters )

Here is an example of sending Serial

void fSendLIDAR_InfoSerialToBrain( void *pvParameters )
{
  struct stu_LIDAR_INFO pxLIDAR_INFO;
  for ( ;; )
  {
    xEventGroupWaitBits (eg, evtGetIMU, pdTRUE, pdTRUE, portMAX_DELAY);
    xSemaphoreTake( sema_LIDAR_FOR_ALARM, xSemaphoreTicksToWait );
    xQueueReceive ( xQ_LIDAR_FOR_ALARM, &pxLIDAR_INFO, QueueReceiveDelayTime );
    xSemaphoreGive( sema_LIDAR_FOR_ALARM );
    int CellCount = 1 ;
    //    Serial.print ( " fSendLIDAR_InfoSerialToBrain " );
    //          // send LIDAR info for alarm
    String sSerial = "";
    sSerial.reserve ( 300 );
    sSerial.concat( "<#," ); //sentence begin
    sSerial.concat( String(ScanPoints) + "," );
    sSerial.concat( String(pxLIDAR_INFO.ServoSweepUp) + "," ); // get direction of scan
    for ( CellCount; CellCount <= ScanPoints; CellCount++ )
    {
      sSerial.concat( String(pxLIDAR_INFO.Range[CellCount]) + "," );
    }
    sSerial.concat( ">" ); //sentence end
    vTaskDelay( 10 );
    SerialBrain.println ( sSerial );
  }
  vTaskDelete( NULL );
} // void fSendLIDAAR_InfoSerialToBrain( void *pvParameters )
////

on an ESP32.