Libreria RestClient.h

Buenos días.
Estoy utilizando la librería "RESTClient.h" y tengo un problema. Estoy programando un Arduino Mega y cogiendo y escribiendo datos en un servidor en una BD MySQL.
La consulta y escritura en mi servidor funciona bien, mi servidor siempre recibe los datos y los devuelve.
El problema que tengo es cuándo el arduino debe recibir las respuestas del servidor, no siempre las recibe. El servidor siempre responde, lo tengo comprobado, pero el arduino no siempre recibe la respuesta y datos. Puede ocurrir que algunas veces si reciba correctamente la respuesta del servidor y otras no, se queda esperando porque no recibe nada.
He hecho todas las comprobaciones que yo puedo hacer y el problema creo que está en que el arduino no recibe la respuesta del servidor y el servidor si que ha contestado.
Estoy perdido, sospecho de algún problema de la librería.
¿Cómo puedo resolverlo?
Gracias y disculpad las molestias.


//#include <Ethernet.h>
//#include <SPI.h>
#include "RestClient.h"
#include <avr/wdt.h>   // Control de prenjades.

RestClient client = RestClient("x.x.x.x"); // ONLINE

int idSonda  = 1020;              // Id de la Sonda, cada sona ha de portar un Id Unica

int OpenClose = 0;                // Aquest var indicarà si hem d'obir el reí o no 0=No 1=Si
int TempsEntreLectures = 2;       // Si son Portes son segons, si son sondes son minuts
int TempsAfegitLectura = 10;      // Temps a afegir al TempsEntreLectures
int OnOff = 0;                    // 0= no gravem 1=si gravem
int TimeOpen = 500;               // Temps que tindrem el relé activat 1000 =1segons
bool BarreraOberta = false;       // Quan hem Obert la barrea pose "true" i si està tancada "false"
//String idTipusSondes = "?";       // Tipus de sonda que llegim
char idTipusSondes[6] = "R";     // Tipus de sonda que llegim


int pinDigital = 7;               // Pin digital. Per defecte, el 7
bool connectat = false;

char userMySQL[] = "rrrrr";                 // MySQL user login username
char passwordMySQL[] = "ttttt";        // MySQL user login password      

void setup()
  {
  //Autoreset
  wdt_enable(WDTO_4S);            // (WDTO_8S) 8segons es el màxim, (WDTO_4S) son 4 !!!
  //Fi autorreset 
  Serial.begin(9600);
  Serial.println();
  Serial.println("*****************************************************");  
  Serial.println("Iniciant SETUP... PortesReleGetPost_22");
  Serial.println("*****************************************************");    
  Serial.print(" -> Idsonda:"); Serial.println(idSonda);
  wdt_reset();
  ActivarRele(0);  //Assegurem que el relé està tancat amb un 0.   
  wdt_reset();  
  Serial.println(" -> Connectant a la xarxa...");
  connectat = client.dhcp();
  Serial.print(" -> IP:"); Serial.println(Ethernet.localIP());  
  Serial.print(" -> Connectats? (0=NO;1=SI) -> "); Serial.println(connectat);  
  if (connectat == 0) delay(10000);  // si es 0, provocarem un reset, pq no tenim xarxa
  wdt_reset();
  LlegirMySQL();
  Serial.println("Fi SETUP");
  Serial.println("*****************************************************"); 
  delay(1000);
  }


void loop() 
  {
  Serial.println(" -> ### 0");  
  wdt_reset();
  LlegirMySQL();  //siii
  if ( (OpenClose > 0) && (OnOff == 1))         //Canvia l'estat del rele
    {
    Serial.println(" -> ### 1");
    wdt_reset();
    ActivarRele(OpenClose);                     //Activem el relé amb el valor de OpenClose (0 => LOW i >=1 => HIGH.  
    Serial.println(" -> ### 2");
    wdt_reset();    
    Serial.println(" -> ### 3"); 
    wdt_reset();
    RegistreMySQL(idSonda, idTipusSondes, OpenClose);          //Creem registre de traçabilitat.
    // Esperem X segons a tornar a posar OpenClose a 0
    wdt_disable();                              // Desactivem el watchdog
    Esperem (TempsAfegitLectura);               // "PeriodeAfegit" Esperem un temps afegit per no estar obrint repetidament
    wdt_enable(WDTO_4S);                        // Activar/Configurar als 4 segons
    wdt_reset();
    ActualitzaSondesMySQL(idSonda, idTipusSondes, 0);     //Canviem l'estat del relé a la BD --> idsonda, tipus de sonda, valor a gravar 
    }
  wdt_disable();
  Serial.println(" -> ### 4");
  // Temps que esperem entre captura i captura, en minuts--------------------    
  Esperem (TempsEntreLectures); //Periode esperem 1, 10 minut,...
  // Fi espera entre dades---------------------------------------------------  
  wdt_enable(WDTO_4S);     //wdt_enable(WDTO_8S);
  }

//PUT  actualitzar registres dades a la taula de "sondes"
void ActualitzaSondesMySQL(int idSondaSQL, char IdTipusSondaSQL[], float ValorSQL)
  {
  String response; 
  char idSondaInsertat[6];
  char ValorInsertar[6];  

  Serial.println(" -> Actualitzant dades al MySQL, taula Sondes,...");
  dtostrf( idSondaSQL , 1, 0, idSondaInsertat);   // zero decimals
  dtostrf( ValorSQL , 1, 0, ValorInsertar);   // dos decimals

  char INSERT_POST[] = "/ausacontrolapi/api/actualitzarSonda?";       // ONLINE: /ausacontrolapi
  char INSERT_BODY[] = "nomUsuari=rrrr&passwordUsuari=yyyyyyy&idSonda=%s&OpenClose=%s&_method=PUT";
  char query[256];

  //PUT
  sprintf(query, INSERT_BODY,idSondaInsertat,ValorInsertar);           // <-- *** Línea modificada ***
  Serial.print(" -> PUT:");
  Serial.println(query);

  response = "";
  client.setHeader("Content-Type: application/x-www-form-urlencoded");
  int statusCode = client.post(INSERT_POST, query, &response);        // <-- *** Línea modificada ***
  Serial.print(" -> Status code from server: ");
  Serial.println(statusCode);
  if (statusCode == 200) BarreraOberta = false;         // Això ho fem per assegurar que a la BD hem modificat l'estat
  Serial.print(" -> Response body from server: ");
  Serial.println(response);
  Serial.println("------------------");   
  }

//POST
void RegistreMySQL(int idSondaSQL, char IdTipusSondaSQL[], float ValorSQL)
  {
  String response; 
  char idSondaInsertat[6];
  char ValorInsertar[6];  

  Serial.println(" -> Gravan registre nou al MySQL...");
  dtostrf( idSondaSQL , 1, 0, idSondaInsertat);   // zero decimals
  dtostrf( ValorSQL , 1, 0, ValorInsertar);   // dos decimals
  
  char INSERT_POST[] = "/ausacontrolapi/api/inserirRegistre?";                                            // <-- *** Línea modificada ***
  char INSERT_BODY[] = "nomUsuari=xxxxx&passwordUsuari=yyyy&idSonda=%s&idTipusSonda=%s&valor=%s";  // <-- *** Línea añadida ***
  char query[256];

  //POST
  sprintf(query, INSERT_BODY, idSondaInsertat, IdTipusSondaSQL, ValorInsertar);           
  Serial.print(" -> POST:");  
  Serial.println(query);

  response = "";
  client.setHeader("Content-Type: application/x-www-form-urlencoded");
  int statusCode = client.post(INSERT_POST, query, &response);      // <-- *** Línea modificada ***
  Serial.print(" -> Status code from server: ");
  Serial.println(statusCode);
  Serial.print(" -> Response body from server: ");
  Serial.println(response);
  Serial.println("------------------");   
  }

//GET
void LlegirMySQL()
  {
  int Control = 0;  
  char *s;
  char *strings[30];
  String response;

  char SELECT_GET[] = "/ausacontrolapi/api/getParamsSonda?nomUsuari=xxxxx&passwordUsuari=yyyyy&idSonda=%s";  
  char query[256];
   
  Serial.println(" -> Llegint dades del MySQL...");
  char idSonaInsertat[6];
  dtostrf( idSonda, 1, 0, idSonaInsertat);   // zero decimals  
  sprintf(query, SELECT_GET, idSonaInsertat);
  Serial.print(" -> GET:");
  Serial.println(query);

  response = "";
  client.setHeader("Content-Type: application/x-www-form-urlencoded");
  int statusCodeGet = client.get(query, &response);
  delay(100);
  Serial.print(" -> Status code from server: ");
  Serial.println(statusCodeGet);  //si es 200 es que ha retornar dades correctament
  if (statusCodeGet==200)
    {
    Serial.println(" -> Lectura correcte, les dades son: ");
    Serial.print(" -> ");Serial.println(response);
    s = strtok(response.c_str(), ";");
    int index=0;
    while (s!=NULL) 
      {
      strings[index]= s;  
      s=strtok(NULL, ";");
      index++;
      }
    Serial.print(" -> ");  
    for(int n = 0; n <= index; n++)
      {   
      if ( n < index)
        {
        Serial.print(n);Serial.print("(");Serial.print(strings[n]);Serial.print(") ");
        } 
      //if (n==2) idTipusSondes = strings[n];    //"Periode" - Temps entre lectures   
      if (n==4) TempsEntreLectures = atol(strings[n]);    //"Periode" - Temps entre lectures 
      if (n==5) OnOff = atol(strings[n]);                 //"OnOff" - Grabem les dades 1=SI i 0=NO
      if (n==6) OpenClose = atol(strings[n]);             //"OpenClose" - Obrir porta 1=SI i 0=NO
      if (n==7) TimeOpen = atol(strings[n]);              //"TimeOpen" - Temps que tindrem el relé clavat
      if (n==8) TempsAfegitLectura = atol(strings[n]);    //"PeriodeAfegit" - Temps que esperarem entre obertures de relé.
      if (TimeOpen >3000 ) TimeOpen = 3000;               //Maxim temps 3 segons
      }    
    Serial.println(); 
    Serial.println("-----------------------------------------------------"); 
    Serial.print(" ->                                Idsonda = "); Serial.println(idSonda);    
    Serial.print(" ->         Tipus de sonda (idTipusSondes) = "); Serial.println(idTipusSondes);    
    Serial.print(" ->         Temps entre lectures (Periode) = "); Serial.println(TempsEntreLectures);  
    Serial.print(" ->                          OnOff (OnOff) = "); Serial.println(OnOff);     
    Serial.print(" ->                  OpenClose (OpenClose) = "); Serial.println(OpenClose);  
    Serial.print(" ->                    TimeOpen (TimeOpen) = "); Serial.println(TimeOpen); 
    Serial.print(" -> Temps afegir a lectura (PeriodeAfegit) = "); Serial.println(TempsAfegitLectura);          
    //Fi Calibratge    
    }
  else
    {
    Serial.println(" -> Error al llegir les dades.");      
    }
    Serial.println("-----------------------------------------------------");      
  }

void ActivarRele(int Valor)   // ha de ser 0 o 1
  {
    //int pin = 7;   //Pin digital 7
    if (Valor >= 1) 
    {
      if (Valor == 1) pinDigital = 7;       // Valor OpenClose = 1 ==> PinDigital 7
      if (Valor == 2) pinDigital = 6;       // Valor OpenClose = 2 ==> PinDigital 6
      if (Valor == 3) pinDigital = 5;       // Valor OpenClose = 3 ==> PinDigital 5
      if (Valor == 4) pinDigital = 4;       // Valor OpenClose = 4 ==> PinDigital 4
    }
  
    pinMode(pinDigital, OUTPUT);  //definir pin como salida 
  
    if (BarreraOberta == false)
      {
      Serial.print(" -> Rele, valor: "); Serial.println(Valor);
      if (Valor == 0) digitalWrite(pinDigital, LOW);       // posarer el Pin en LOW 
      if (Valor >= 1)
      {
        Serial.println(" -> Rele ON");  
        digitalWrite(pinDigital, HIGH);      // posar el Pin en HIGH 
      }
      wdt_reset();  
      delay(TimeOpen);               // manetenim el relé clavat 
      wdt_reset();
      // Tornem a deixar el Pin en LOW 
      Serial.println(" -> Rele Off");  
      digitalWrite(pinDigital, LOW);        // posar el Pin en LOW sempre acaba en "0"
      if (Valor >= 1) BarreraOberta = true;
      }
    else Serial.println(" -> La barrera ja ha estat oberta previament");
  }

// Funció temps d'espera entre captura de dades, en minuts-------------------
void Esperem (int segons)  
  {
  // Tornem a posar el temps afegit a 0
  TempsAfegitLectura = 0;    
  Serial.print(" -> Esperant (segons) :");
  Serial.print( segons);
  Serial.print(" ");
  for (int a=0; a<segons; a++)
    {      
    delay(900);  //60000 es un minut   si son sondes 60000 pq son minuts. Si son portes, segons i posem 1000
    Serial.print(".");
    }   
  Serial.println (" ");  
  }
// Fi funció temps d'espera--------------------------------------------------

No aclaras que Arduino estas utilizando, o si estas utilizando un esp8266.
El problema puede pasar por los delays de tu código, puedes estar perdiendo mensajes. Eliminalos de tu código y vuelve aprobar.
Saludos

Grácias "PeterKantTropus".
El codigo está provado con un Mega mas shild Ethernet.

Los "deleys" estan todos suprimidos, entre el query y la respuesta.
El codigo se queda pendiente de recibir el "statusCode" !!!
Pero no siempre, a veces funciona bien y a veces no.
Pero el servidor, siempre recive los datos y contesta.
Aqui es donde me tiene despistado.

  response = "";
  client.setHeader("Content-Type: application/x-www-form-urlencoded");
  int statusCode = client.post(INSERT_POST, query, &response);        // <-- *** Línea modificada ***
  Serial.print(" -> Status code from server: ");
  Serial.println(statusCode);
  if (statusCode == 200) BarreraOberta = false;         
  Serial.print(" -> Response body from server: ");
  Serial.println(response)

La combinación MEGA (lo mismo con UNO) shield Ethernet requiere fuente de alimentación externa. Con USB y peor si es 2.0 esta como justa en corriente.
Asegúrate de que tenga buena alimentación con fuente externa que provea al menos 7V 1A (aunque no lo va a usar). Todo lo que este por encima de 7V esta bien y no pasarse de 12V para evitar recalentamiento del regulador del MEGA.
Hablo de cosas que me ocurrieron a mi con el shield Ethernet.
Malos comportamientos que desaparecieron con fuente externa.
Otra cosa importante!
Si estas con fuente externa no reprogrames con conector USB estando alimentado con fuente externa.
Asi que si lo alimentas con fuente externa como ves el USB via monitor Serie? La solución es en un cable USB al que le cortas el terminal 5V.
A mi se me quemó un UNO de este modo.

Gracias Surbyte.
Esta tarde he pasado el programa a una "Feather M4 Expres" con su shild Ethernet.
Con la bateria externa puesta y hace lo mismo. El problema no es de alimentación.
Lo que me tiene muy despistado, es que puede funcionar bien tres veces y fallar las tres siguentes.

Se queda en la linia:

int statusCodeGet = client.get(query, &response);

si ejecuto el Get

int statusCode = client.post(INSERT_POST, query, &response); 

si ejecuto el post

Esperando el "statusCodeGet" o "statusCode" en el post.

Tiene pinta a problema en la librería, pero claro, lo más probable es un error mío.
Si ejecuto la API des del navegador, no falla nunca y me devuelve lo que toca.
En el servidor el Arduino graba la información, pero ha "veces" no recibo el Statucode y allí se queda el programa. Pero a veces si recibo el "200" que es correcto o "0" que no es correcto, pero no se cuelga !!!

Alguna alternativa a la libreria RestClient.h ?

ostras, si añado el puerto, creo que no falla !!!

RestClient client = RestClient("x.x.x.x,80");

Use a local IP and an explicit port:

RestClient client = RestClient("192.168.1.50",5000);

No cantaré victoria todavía, lo probaré bien !!!

ups !!! siempre me retorna un "0" y no graba los datos, el puerto si es el 80.
No se cuelga nunca.

Buenos dias, he dedicado un ratito esta mañana buscando informacion y continuo sin saber donde tengo el problema.
¿Dentro de una libreria puedo poner "serial.println ("1")" por ejemplo, para poder seguir los pasos ?
Quiero saber donde se queda el programa "colgado", y em mi caso tiene que ser en algun paso de la libreria "RestClient" o en alguna de las librerias que esta utiliza.
No he echo nunca estas cosas !!!

La librería que estas utilizando es para Arduino Zero y MKR1000, de 32 bits.
Que es un FORK de esta libreria.

Grácias PeterKantTropus.
Lo he provado con un MKR1000, Feather M4 E, Arduino Mega.
Ayer y esta mañana lo he provado con el "Feather M4 E"
Hace lo mismo en todas !!!
A veces funciona y a veces no funciona, sin yo tocar nada.

Ya he encontrado donde se queda "colgado" el programa, en la libreria RestClient, fichero RestClient.cpp

Se queda en el bucle:
while (client.connected())

Porque no recive nada, pero mi servidor ha contestado !!!

int RestClient::readResponse(String* response) {

  // an http request ends with a blank line
  boolean currentLineIsBlank = true;
  boolean httpBody = false;
  boolean inStatus = false;

  char statusCode[4];
  int i = 0;
  int code = 0;

  if(response == NULL){
    HTTP_DEBUG_PRINT("HTTP: NULL RESPONSE POINTER: \n");
  }else{
    HTTP_DEBUG_PRINT("HTTP: NON-NULL RESPONSE POINTER: \n");
  }

  HTTP_DEBUG_PRINT("HTTP: RESPONSE: \n");
  while (client.connected()) {
    HTTP_DEBUG_PRINT(".");

    if (client.available()) {
      HTTP_DEBUG_PRINT(",");

      char c = client.read();
      HTTP_DEBUG_PRINT(c);

      if(c == ' ' && !inStatus){
        inStatus = true;
      }

      if(inStatus && i < 3 && c != ' '){
        statusCode[i] = c;
        i++;
      }
      if(i == 3){
        statusCode[i] = '\0';
        code = atoi(statusCode);
      }

      if(httpBody){
        //only write response if its not null
        if(response != NULL) response->concat(c);
      }
      else
      {
          if (c == '\n' && currentLineIsBlank) {
            httpBody = true;
          }

          if (c == '\n') {
            // you're starting a new line
            currentLineIsBlank = true;
          }
          else if (c != '\r') {
            // you've gotten a character on the current line
            currentLineIsBlank = false;
          }
      }
    }
  }

  HTTP_DEBUG_PRINT("HTTP: return readResponse3\n");
  return code;
}

Alguin sabe si esto es correcto?

HTTP_DEBUG_PRINT("HTTP: return readResponse3\n");

El "3" es correcto?

Buenas tarde, alguin sabe en que momento "client.connected()" canvia de estado a no conectado?
Gracias.

No es importante el "3" ya que solo es para debug, equivale a

Serial.print("HTTP: return readResponse3\n");

La función connected() está en Client.h, fijate como trabaja.

Saludos

Gracias Gatul.
Esto ya no se si està a mi nivel.

La Client.h:

#ifndef client_h
#define client_h
#include "Print.h"
#include "Stream.h"
#include "IPAddress.h"

class Client : public Stream {

public:
  virtual int connect(IPAddress ip, uint16_t port) =0;
  virtual int connect(const char *host, uint16_t port) =0;
  virtual size_t write(uint8_t) =0;
  virtual size_t write(const uint8_t *buf, size_t size) =0;
  virtual int available() = 0;
  virtual int read() = 0;
  virtual int read(uint8_t *buf, size_t size) = 0;
  virtual int peek() = 0;
  virtual void flush() = 0;
  virtual void stop() = 0;
  virtual uint8_t connected() = 0;
  virtual operator bool() = 0;
protected:
  uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); };
};

#endif

" virtual uint8_t connected() = 0;"

La RestClient.h, el While no sale del bucle mientras esta conectada, no se como pudedo saber que esta esperando para decidir que se desconecta.
Creo que por este camino no soy capaz de continuar !!!

A ver, creo que tenia mal inicializada la Ethernet:

Serial.println("Connectant a la xarxa...");
  connectat = client.dhcp();

  byte mac[] = {0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };   
  if (Ethernet.begin(mac) == 0) 
    {
    Serial.println("Failed to configure Ethernet using DHCP");
    }

He forzado un MAC y parece que no falla !!!
He visto que en el DHCP server, habia dieferentes IPs con la misma MAC.
Si yo pongo las MAC por software, cada IP tiene su MAC.
Con este ultimo arreglillo, funciona bien.