Go Down

Topic: Problema con String.indexOf (Read 330 times) previous topic - next topic

hgsiabato

Buen día a todos. Tengo un problema que no le encuentro explicación. Tengo un webclient que recupera información de una página web cada 3 segundos y luego con indexOf busca dentro del código obtenido los parámetros necesarios. Aproximadamente la primera hora funciona perfectamente pero luego de esto devuelve -1, a pesar que en la variable String se observa que está el texto que uso como parámetro de búsqueda de la función indexOf. No se si se saturará después de muchos intentos, o si tengo que restablecer la variable que recoge el resultado. Agradezco cualquier ayuda.

ArduMyth

#1
Apr 23, 2018, 11:09 am Last Edit: Apr 23, 2018, 11:11 am by ArduMyth
"Returns The index of val within the String, or -1 if not found"

No encuentra lo que buscas = -1.

Es común en otros lenguajes con esta misma función. No obstante bastaba con mirar la documentación:
https://www.arduino.cc/reference/en/language/variables/data-types/string/functions/indexof/

Ahora bien, por qué falla no lo podemos saber. No hay código.
No obstante para algo así, usar a Arduino de servidor me parece excesivo. No está diseñado para esto.
Una raspberry sería mejor dado que es un microprocesador no un microcontrolador, e igual si tuviese que leer datos de una web no lo haría directamente con Arduino sino con php y expresiones regulares (No por algo es el método que se usa en todas las webs de "búsquedas/comparaciones" para seguros y viajes, ya después Arduino sólo se encargaría de la parte usuario(cliente).
Y es muy simple tener un servidor local en tu ordenador con php sin necesidad de comprar un hosting.

Saludos.

noter

Si funciona bien y deja de funcionar pasada una hora, así de primeras se me ocurre que puede ser que el cliente dejé de conectar, o que la memoria se llene.
Pin tu código y te podremos dar alguna idea para encontrar y tal vez corregir el problema.

hgsiabato

"Returns The index of val within the String, or -1 if not found"

No encuentra lo que buscas = -1.

Es común en otros lenguajes con esta misma función. No obstante bastaba con mirar la documentación:
https://www.arduino.cc/reference/en/language/variables/data-types/string/functions/indexof/

Ahora bien, por qué falla no lo podemos saber. No hay código.
No obstante para algo así, usar a Arduino de servidor me parece excesivo. No está diseñado para esto.
Una raspberry sería mejor dado que es un microprocesador no un microcontrolador, e igual si tuviese que leer datos de una web no lo haría directamente con Arduino sino con php y expresiones regulares (No por algo es el método que se usa en todas las webs de "búsquedas/comparaciones" para seguros y viajes, ya después Arduino sólo se encargaría de la parte usuario(cliente).
Y es muy simple tener un servidor local en tu ordenador con php sin necesidad de comprar un hosting.

Saludos.
Gracias por responder, Arduino se conecta como cliente no como servidor. La variable String TIENE la palabra que debe buscar pero aún así devuelve -1. Imprimí en el monitor todo el texto de la variable y puedo darme cuenta que si está la palabra a buscar.

hgsiabato

Si funciona bien y deja de funcionar pasada una hora, así de primeras se me ocurre que puede ser que el cliente dejé de conectar, o que la memoria se llene.
Pin tu código y te podremos dar alguna idea para encontrar y tal vez corregir el problema.
Gracias por tu respuesta noter. Este es el código completo:

Code: [Select]

/*
  Web client

 This sketch connects to a website (http://www.google.com)
 using an Arduino Wiznet Ethernet shield.

 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13

 created 18 Dec 2009
 by David A. Mellis
 modified 9 Apr 2012
 by Tom Igoe, based on work by Adrian McEwen

 */

#include <SPI.h>
#include <Ethernet.h>

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
//IPAddress server(74,125,232,128);  // numeric IP for Google (no DNS)
char server[] = "https://mipaginaweb.com";    // name address for Google (using DNS)
unsigned long lastConnectionTime = 0;             // last time you connected to the server, in milliseconds
const unsigned long postingInterval = 3L * 1000L; // delay between updates, in milliseconds
// the "L" is needed to use long type numbers
String sCode;

// Set the static IP address to use if the DHCP fails to assign
IPAddress ip(192, 168, 0, 177);

// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
EthernetClient client;

void Conectar(){
   // start the Ethernet connection:
  // give the Ethernet shield a second to initialize:
  delay(1000);
  client.stop();
  //Serial.println("connecting...");

  // if you get a connection, report back via serial:
  if (client.connect(server, 80)) {
    //Serial.println("connected");
    // Make a HTTP request:
    client.println("GET /prueba.php HTTP/1.1");
    client.println("Host: mipaginaweb.com");
    client.println("Connection: close");
    client.println();
    lastConnectionTime = millis();
  } else {
    // if you didn't get a connection to the server:
    //Serial.println("connection failed");
  }
}

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  pinMode(8, OUTPUT);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // try to congifure using IP address instead of DHCP:
    Ethernet.begin(mac, ip);
  }
  Conectar();
}

void loop() {
  // if there are incoming bytes available
  // from the server, read them and print them:
  if (client.available()) {
    char c = client.read();
    sCode += c;
    //Serial.print(c);
  }

  // if the server's disconnected, stop the client:
  if (!client.connected()) {
      //Serial.println("disconnecting.");
      client.stop();
      if (sCode != ""){
        int pos_ini=sCode.indexOf("[DATA]");
        if (pos_ini>=0) {
          int pos_fin = sCode.indexOf("[/DATA]",pos_ini);
          if (pos_fin>=0) {
            String sDatos = sCode.substring(pos_ini + 6,pos_fin);
            String sValor = sDatos.substring(8,9);
            if (sValor == "1"){
              digitalWrite(8, HIGH);
            }
            else
            {
              digitalWrite(8, LOW);
            }
          }
        }
        else
        {
          Serial.println("==================================================");
          Serial.println(sCode);
          Serial.println("==================================================");
          Serial.println(pos_ini);
          Serial.println("==================================================");
        }
        sCode = "";
      }
  }
  if (millis() - lastConnectionTime > postingInterval) {
    Conectar();
  }
}


Como puedes ver el último else se ejecuta cuando no encuentra [DATA] y me imprime en el monitor tanto el contenido de la variable sCode como el valor de pos_ini y puedo ver que si está [DATA] en la variable y sigue siendo -1 el resultado. No es problema de conexión con la página porque si devuelve todo el código correctamente, tiene que ser problema del arduino. Uso arduino Leonardo.

noter

¿Osea que por serial te sale que la cadena sCode es "[Data]....[/Data]" y pos_ini es -1?

La única posibilidad que veo es que se sature la memoria.
Haz la siguiente prueba. Agrega esta función a tu código
Code: [Select]

int freeRam () {
  extern int __heap_start, *__brkval;
  int v;
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}


Y monitoriza, además de scode y pos_ini, el valor freeRam() a ver si la memoria libre va decreciendo.

hgsiabato

¿Osea que por serial te sale que la cadena sCode es "[Data]....[/Data]" y pos_ini es -1?

La única posibilidad que veo es que se sature la memoria.
Haz la siguiente prueba. Agrega esta función a tu código
Code: [Select]

int freeRam () {
  extern int __heap_start, *__brkval;
  int v;
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}


Y monitoriza, además de scode y pos_ini, el valor freeRam() a ver si la memoria libre va decreciendo.
Hice lo que me dijiste, al comienzo devolvía 815, luego de unos 20 min 375 y justo cuando dejó de funcionar indexOf tampoco funcionó más la función de memoria libre. Yo creo que si es problema de la memoria interna. Cómo puedo hacer para irla liberando?

hgsiabato

Seguí haciendo pruebas y la memoria baja hasta 158 y ahí deja de funciona el programa.

hgsiabato

Le hice algunas modificaciones pero aún así baja de 853 a 157 de un momento a otro.

Code: [Select]

#include <SPI.h>
#include <Ethernet.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
char server[] = "https://homeotica.000webhostapp.com";
unsigned long lastConnectionTime = 0;
const unsigned long postingInterval = 3L * 1000L;
String sCode;
IPAddress ip(192, 168, 0, 177);
EthernetClient client;

void Conectar(){
  delay(1000);
  client.stop();
  if (client.connect(server, 80)) {
    client.println("GET /prueba.php HTTP/1.1");
    client.println("Host: homeotica.000webhostapp.com");
    client.println("Connection: close");
    client.println();
    lastConnectionTime = millis();
  } else {
    //Serial.println("connection failed");
  }
}

int freeRam () {
  extern int __heap_start, *__brkval;
  int v;
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}

void setup() {
  sCode.reserve(500);
  Serial.begin(9600);
  pinMode(8, OUTPUT);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  if (Ethernet.begin(mac) == 0) {
    Serial.println F("Failed to configure Ethernet using DHCP");
    Ethernet.begin(mac, ip);
  }
  Conectar();
}

void loop() {
  if (client.available()) {
    char c = client.read();
    sCode += c;
    //Serial.print(c);
  }
  if (!client.connected()) {
      //Serial.println("disconnecting.");
      client.stop();
      if (sCode != ""){
        int pos_ini=sCode.indexOf("[DATA]");
        if (pos_ini>=0) {
          Serial.println F("******************************");
          Serial.println(freeRam());
          Serial.println F("******************************");
          int pos_fin = sCode.indexOf("[/DATA]",pos_ini);
          if (pos_fin>=0) {
            String sDatos;
            sDatos.reserve(10);
            sDatos = sCode.substring(pos_ini + 6,pos_fin);
            String sValor;
            sValor.reserve(1);
            sValor = sDatos.substring(8,9);
            if (sValor == "1"){
              digitalWrite(8, HIGH);
            }
            else
            {
              digitalWrite(8, LOW);
            }
          }
        }
        else
        {
          Serial.println F("==================================================");
          //Serial.println(sCode);
          Serial.println(freeRam());
          Serial.println F("==================================================");
        }
        sCode = "";
      }
  }
  if (millis() - lastConnectionTime > postingInterval) {
    Conectar();
  }
}

Kike_GL

Cuando deje de funciona prueba presionar boton reset a ver que pasa.
Saludos, Kike_GL

ArduMyth

A todas estas ¿Has probado a ver que pasa si en vez de hacerlo cada 3 segundos es cada 10 ó 30? Quiero decir que si aumentando el tiempo ese error tarda más en aparecer o ni ocurre puede ser un tema de memoria como apunta @noter. Dale un respiro al Arduino a ver qué ocurre.

Otra cuestión ¿El hosting del que lees la página es tuyo? No creo que sea por lo que te comento a continuación pero es algo que no se suele tener en cuenta leyendo webs. Si "bombardeas" webs a peticiones y no son tuyas hay maneras de detener ese tráfico para evitar caídas o bloqueos.

hgsiabato

Cuando deje de funciona prueba presionar boton reset a ver que pasa.
Si hago eso vuelve a funcionar normalmente hasta que pasa cierto tiempo y vuelve a fallar.

A todas estas ¿Has probado a ver que pasa si en vez de hacerlo cada 3 segundos es cada 10 ó 30? Quiero decir que si aumentando el tiempo ese error tarda más en aparecer o ni ocurre puede ser un tema de memoria como apunta @noter. Dale un respiro al Arduino a ver qué ocurre.

Otra cuestión ¿El hosting del que lees la página es tuyo? No creo que sea por lo que te comento a continuación pero es algo que no se suele tener en cuenta leyendo webs. Si "bombardeas" webs a peticiones y no son tuyas hay maneras de detener ese tráfico para evitar caídas o bloqueos.
No puedo hacerlo cada 10 o 30 segundos porque necesito que la respuesta sea lo más en tiempo real posible. De hecho si se pudiera cada segundo sería lo ideal. En cuanto al hosting sin problema alguno, no alcanzo ni al 5% de las peticiones diarias que puedo hacer a la página.

Hay alguna forma de "resetear" el arduino desde código cada cierto tiempo?

hgsiabato

Al final pude hacer el reset conectando directamente un cable al pin de reset, aunque no quedé conforme con esta solución ya que la idea era poder saber en dónde era que se ocupaba la memoria, pero por más veces que veo el código no entiendo en donde está el error.

surbyte

El problema no esta acá?

Code: [Select]
String sDatos;
sDatos.reserve(10); <=== allocate 10 bytes
sDatos = sCode.substring(pos_ini + 6,pos_fin);
String sValor;
sValor.reserve(1);   <=== allocate 10 bytes


en cada ciclo reservas 11 bytes de SRAM.
Realmente son necesarios. Nunca he visto que alguien use esto para hacer las funciones que estas usando?

prueba esta parte de código asi

Code: [Select]
if (pos_fin>=0) {
                  String sDatos = "";
                  sDatos = sCode.substring(pos_ini + 6,pos_fin);
                  if (sDatos.substring(8,9)== "1"){
                      digitalWrite(8, HIGH);
                  }
                  else
                  {
                      digitalWrite(8, LOW);
                  }
              }

hgsiabato

#14
Apr 25, 2018, 07:30 pm Last Edit: Apr 25, 2018, 11:05 pm by surbyte
Así como dices era como yo lo tenía al principio, de hecho si miras el post #4 de este hilo verás que así estaba, pero leyendo la forma de administrar la memoria, aconsejaban reservar los bytes de acuerdo a las necesidades para evitar que la variable fuera creciendo con el paso del tiempo y siempre permaneciera del mismo tamaño, pero de ninguna de las dos formas funcionó. Ya no se por donde más modificarle.


Moderador: No repitas lo que se lee arriba.

Go Up