Obtener datos de un string obtenido via http en Arduino ?

Saludos a todo el foro, estoy trabajando en un pequeño proyecto; un Dataloger basado en ESP32 que en su momento subira datos a una "nube" de internet.

Tengo dudas sobre como obtener de mejor manera o "elegante", pero con seguridad, datos que vienen en una cadena obtenida via http.

Para ejemplificar, dejo el codigo, quiero obtener la Hora en formato Unix desde la siguiente Api:

http://worldtimeapi.org/api/ip

C++:
/*Obtener la hora en formato UNIX Time
 * desde un servidor ntp y la API correspondiente
 * */


#include <WiFi.h>
#include <HTTPClient.h>

// Datos de la red WiFi que sera utilizada
  const char* ssid     = "Mi antena"; //Nombre de la antena del router
  const char* password = "6U3GCU84T11X";//Contraseña del router

void setup(){
  //iniciamos comunicacion serial para monitorear el programa
  Serial.begin(115200);
  
  // Comenzamos por conectarnos al servicio Wifi que da servicio de Internet
  Serial.println();
  Serial.print("Conectandose a ");
  Serial.println(ssid);
    //Solicitamos servicio al Enrutador Wifi
    WiFi.begin(ssid, password);
    // El ciclo continuara hasta se obtenga el servicio
        while (WiFi.status() != WL_CONNECTED) {
          delay(500);
          Serial.print(".");
          }
    //Una vez conectado (obtenemos la direccion IP Local obtenida via DCHP)
    Serial.println("");
    Serial.println("Direccion IP Local: ");
    Serial.println(WiFi.localIP());
}

void loop() {

datos();//llamamos a la subrutina datos

  delay(5000);// este delay es meramente por depuracion.
    
  }


  void datos(){

    //Verificamos el estatus de la conexion WiFi
    if(WiFi.status()== WL_CONNECTED){
      //Iniciamos el cliente Wifi
      WiFiClient client;

      HTTPClient http;
        
        //Declaramos las constantes tanto para el servidor NTP y La API
        const char *ntpServer = "pool.ntp.org";
        const char *timeApiUrl = "http://worldtimeapi.org/api/ip";

        //iniciamos la peticion de la API
        http.begin(timeApiUrl);

        //Obtenemos el codigo http de respuesta (si es 200 entonces tendremos una conexion valida)
        int httpCode = http.GET();

          if (httpCode != 200){
            Serial.println("No se logro obtener datos\r\n");
            configTime(0, 0, ntpServer);
          return;
          }
    //obtenemos la cadena de respuesta de la API y la asignamos nuestra variable respuesta
    String respuesta = http.getString();

        //terminamos la sesion http
        http.end();


  /* monitoreamos el string y rastremos tanto el inicio y final de la informacion que requerimos,
  en  este caso buscamos el dato que viene despues de "unixtime", como podemos ver la cadena es similar a esto:

{"abbreviation":"CDT","client_ip":"189.216.207.201","datetime":"2022-06-19T23:34:24.927078-05:00","day_of_week":0,"day_of_year":170,"dst":true,"dst_from":"2022-04-03T08:00:00+00:00","dst_offset":3600,"dst_until":"2022-10-30T07:00:00+00:00","raw_offset":-21600,"timezone":"America/Mexico_City","unixtime":1655699664,"utc_datetime":"2022-06-20T04:34:24.927078+00:00","utc_offset":"-05:00","week_number":24}

Nota.- Es una cadena json, sin embargo no interesa procesar todas las variables o datos, solo lo que interesa.
 
Nos valemos de la funcion indexOF y subtring para "enfocarnos" con precision
 
  */
  Serial.println("Cadena Obtenida de la API:");
  Serial.println(respuesta);
  Serial.println("Posicion inicial de la cadena buscada");
  Serial.println(respuesta.indexOf("\"unixtime\":")+11);
  Serial.println("Posicion Final de la cadena buscada");
  Serial.println (respuesta.indexOf("\"utc_datetime\":")-1);
  Serial.println("Imprimimos la extraccion de la cadena;");
  Serial.println (respuesta.substring(respuesta.indexOf("\"unixtime\":")+11,respuesta.indexOf("\"utc_datetime\":")-1));
//una vez que conocemos el principio y fin de la informacion que requerimos la declaramos y convertimos desde la cadena obtenida
    long unixtime ((respuesta.substring(respuesta.indexOf("\"unixtime\":")+11,respuesta.indexOf("\"utc_datetime\":")-1).toInt()));
//Monitoreamos la variable ya convertida a long
 
  Serial.println(unixtime);
 
    }
  }

Como podran comprobar, si logro mi cometido, de echo ya en dos sentencias:

String respuesta = http.getString();

long unixtime ((respuesta.substring(respuesta.indexOf("\"unixtime\":")+11,respuesta.indexOf("\"utc_datetime\":")-1).toInt()));


Lo que no estoy seguro si este metodo de usar las funciones indexOF y subtring son la mejor manera.

¿Ustedes que opinan? quizas me puedan ayudar a mejorar mi codigo.

Como siempre, mucho apreciare sus comentarios.
 
Eso se usa mucho en lenguajes de alto nivel, si el uC se la banca, no lo veo mal.

Yo para buscar algo en un string usando C (no C++), utilizo la función "strstr" que tiene este prototipo:

C:
char *strstr(const char *haystack, const char *needle)

Un ejemplo de su uso:

C:
char *ptr, *ptr_tipo_msj;
....
  
ptr_tipo_msj=strstr(buff_uart1_rx, "+IPD,");     
if(!ptr_tipo_msj)
{
    DEBUGOUT("---> Analizar Trama: No se encontro +IPD <---\n");
    return -1;
}
....

//Opero desde el "ptr_tipo_msj"  en vez de "buff_uart1_rx"

Hay un buffer global llamado "buff_uart1_rx" que es del tipo (char *), que ahí recibo lo que me llega por puerto serie, luego con la función "strstr(...)" busco el string "+IPD," y si lo encuentra, la dirección en memoria de la primera aparición de ese string lo guarda en ptr_tipo_msj (apunto al buff_uart1_rx, pero con el corrimiento de la aparición).

Lo que si, evitaría la repetición sucesiva del llamado respuesta.indexOf, si ya lo obtuviste una vez, no repitas la misma búsqueda, simplemente guardalo en una variable. Lo mismo si el string es de un tamaño preestablecido, tal vez te podrías evitar el substring con strncpy (pero nuevamente, eso es C). Pero si al uC le da yo que se, vale.
 
Última edición:
Arriba