boblemaire / asyncHTTPrequest

asynchronous HTTP for ESP using ESPasyncTCP. Works like XMLHTTPrequest in JS.
GNU General Public License v3.0
64 stars 31 forks source link

Want to make 2 different requests, but how to say to the "void requestCB" function to which requests the result belongs ? #45

Closed Rollmops67 closed 1 year ago

Rollmops67 commented 1 year ago

Hello !

Rather a question than an issue :

I'm new to asyncHTTPrequest. I generally use the standard HTTPClient, but I'm looking for an asynchronous solution.

I did try the code in the "Examples" section and it works fine to extract one value (in my case "Pedf") But I would like to extract another value from another request at a different url. So in my sketch I prepared 2 functions to call, "sendRequest_0()" and "sendRequest_1()"

But how to say to the "void requestCB(......" function which value to extract ?

I think there must be a very simple solution, but I'm not familiar with the syntax of this library.

Thanks in advance for any help !

Roland

Here my code for a better understanding (runs on an ESP32)

#include <WiFi.h>
#include <AsyncTCP.h>
#include <asyncHTTPrequest.h>

unsigned long top_lect;
int intervalle = 5000 ; 

const char* ssid     = "xxxxxxxxxx";
const char* password = "yyyyyyyyyyyyyyy";
const int TimeOut_connexion =40;
int timeOut_counter =0;

float Pedf;
float Psol;

asyncHTTPrequest request;

// First request
void sendRequest_0()   // to gather the responseText() for the "Pedf" value
{
    if(request.readyState() == 0 || request.readyState() == 4)
    {
        request.open("GET", "http://192.168.1.12/emeter/0");
        request.send();
    }
}

/*********** The second request I would like to make  ********************
*
*void sendRequest_1()   //    // to gather the responseText() for a second value
*{
*    if(request.readyState() == 0 || request.readyState() == 4)
*    {
*        request.open("GET", "http://192.168.1.12/emeter/1");
*        request.send();
*    }
*}
*
************ The second request I would like to make END *****************/

void requestCB(void* optparm, asyncHTTPrequest* request, int readyState)
{
    if(readyState == 4)
    {
 //       Serial.println(request->responseText());
        Pedf = atof(((request->responseText()).substring(9,18)).c_str());
        Serial.println(Pedf);
    }
}

void setup()
{
  setCpuFrequencyMhz(80);     // réglage de la fréquence de la CPU (80, 160 ou 240 Mhz, en dessous le WiFi ne marche pas)

  Serial.begin(115200);
  delay(2000);

  Serial.print("Connection au WiFi...");

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
    {
      delay(250);
      Serial.print(".");
      timeOut_counter++;
      if (timeOut_counter > TimeOut_connexion) ESP.restart();   // redémarrage de l'ESP si pas de connexion pendant 10 sec
    }

  Serial.println("\n");
  Serial.println("Adresse IP : "+(WiFi.localIP().toString()));

  request.onReadyStateChange(requestCB);

}

void loop() 
{
  if (top_lect+intervalle<millis())             // condition vraie toutes les "intervalle" secondes
    {top_lect=millis(); sendRequest_0(); }        // aller à la routine de lecture des données du ShellyEM
}
boblemaire commented 1 year ago

Just to be clear, an instance of this class can only handle one request at a time. That said:

One solution is to simply change the callback to a different appropriate function prior to each request.

Another solution is to use the callback parameter to point to something that can be used to differentiate between the various requests.

Rollmops67 commented 1 year ago

Hello and thank you for the fast answer !

Not knowing very well AsyncHTTPrequest and it different syntaxes (there is not much information) your 2 propositions are not of big help...

Change the callback to a different appropriate function, why not, but there are not many examples I can look how to do, and what function to use...

I think that your second solution is maybe related to the "void* optparm" option in the "void requestCB" function ? But I tried to figure out how it works but I can't find where this "optparm" is defined and how to redirect (??) the callback with it. Do you maybe have an example ?

TIA !

Roland

boblemaire commented 1 year ago

Maybe something like this:

// First request
void sendRequest_0()   // to gather the responseText() for the "Pedf" value
{
    if(request.readyState() == 0 || request.readyState() == 4)
    {
        request.onReadyStateChange(request1CB);
        request.open("GET", "http://192.168.1.12/emeter/0");
        request.send();
    }
}

void sendRequest_1()   //    // to gather the responseText() for a second value
{
    if(request.readyState() == 0 || request.readyState() == 4)
    {
        request.onReadyStateChange(request2CB);
        request.open("GET", "http://192.168.1.12/emeter/1");
        request.send();
    }
}

void request1CB(void* optparm, asyncHTTPrequest* request, int readyState)
{
    if(readyState == 4)
    {
 //       Serial.println(request->responseText());
        Pedf = atof(((request->responseText()).substring(9,18)).c_str());
        Serial.println(Pedf);
    }
}

void request2CB(void* optparm, asyncHTTPrequest* request, int readyState)
{
    if(readyState == 4)
    {
 //       Serial.println(request->responseText());
        Pedf = atof(((request->responseText()).substring(9,18)).c_str());
        Serial.println(Pedf);
    }
}
Rollmops67 commented 1 year ago

Ohhh thanks.

Ah, its the "request.onReadyStateChange(requestxxx);" wich does the magic !

i will try it.

Roland

Rollmops67 commented 1 year ago

I just tried it, with the result that the ESP32 crashes each time the 2 requests are launched at the same time. I changed my code so the first request starts every 5 seconds, and the second request 2,5 seconds after, and now it works !

Many many thanks !

Roland

Rollmops67 commented 1 year ago

Edit :

Oooops, After about 10 minutes it crashed, with a guru meditation error :

23:24:01.076 -> Guru Meditation Error: Core  1 panic'ed (InstrFetchProhibited). Exception was unhandled.
23:24:01.076 -> 
23:24:01.076 -> Core  1 register dump:
23:24:01.076 -> PC      : 0x00440022  PS      : 0x00060930  A0      : 0x820044f1  A1      : 0x3fca6b50  
23:24:01.076 -> A2      : 0x3fca2b78  A3      : 0x40010000  A4      : 0x3fca2b70  A5      : 0x0000000c  
23:24:01.076 -> A6      : 0x02c95354  A7      : 0x00ffffff  A8      : 0x820043f5  A9      : 0x3fca6b40  
23:24:01.076 -> A10     : 0x3fca2b78  A11     : 0x3fca6b5c  A12     : 0x3fca6b58  A13     : 0x00000000  
23:24:01.076 -> A14     : 0x00000001  A15     : 0x3fca2d40  SAR     : 0x0000000a  EXCCAUSE: 0x00000014  
23:24:01.076 -> EXCVADDR: 0x00440020  LBEG    : 0x400570e8  LEND    : 0x400570f3  LCOUNT  : 0xffffffff  
23:24:01.076 -> 
23:24:01.076 -> 
23:24:01.076 -> Backtrace: 0x0044001f:0x3fca6b50 0x420044ee:0x3fca6b80 0x42004504:0x3fca6ba0 0x4200481e:0x3fca6bc0
23:24:01.076 -> 
23:24:01.076 -> 
23:24:01.076 -> 
23:24:01.076 -> 
23:24:01.076 -> ELF file SHA256: a65d66640a0063d8
23:24:01.076 -> 
23:24:01.076 -> Rebooting...
23:24:01.076 -> ESP-ROM:esp32s3-20210327
23:24:01.076 -> Build:Mar 27 2021
23:24:01.076 -> rst:0xc (RTC_SW_CPU_RST),boot:0x8 (SPI_FAST_FLASH_BOOT)
23:24:01.076 -> Saved PC:0x420195f5
23:24:01.076 -> SPIWP:0xee
23:24:01.076 -> mode:DIO, clock div:1
23:24:01.076 -> load:0x3fce3808,len:0x44c
23:24:01.076 -> load:0x403c9700,len:0xbe4
23:24:01.076 -> load:0x403cc700,len:0x2a38
23:24:01.076 -> entry 0x403c98d4

Roland

boblemaire commented 1 year ago

Simultaneous requests work with the ESP8266. The ESP32 is a different animal. I don't use this with ESP32 because there is really no need to provide the asynchronous HTTP functionality with ESP32. You can just create a FREERTOS task to do the transaction with either HTTPclient or the underlying esp_http_client and blocking will only affect that task while your other tasks continue to execute. You get the added benefit of being able to use both processors.

Rollmops67 commented 1 year ago

OK, I will try this way.

Thanks for the time spend.

Roland