Consulta lectura datos desde data bucket - Reading data from data bucket

Estimados, tengo una consulta: es posible que al momento de arrancar un dispositivo éste lea el ultimo valor que se haya guardado en un data bucket?

Puntualmente estoy trabajando con un WeMos D1R2 (no creo que haga ninguna diferencia) y la idea es que ante un reseteo o perdida de alimentación no se pierda un valor acumulativo que se va guardando durante la ejecución del programa.

Gracias.

Julian.


I have a question: is it possible that at the moment of starting a device it reads the last value that has been saved in a data bucket?

I am working with a WeMos D1R2 (I do not think it makes any difference) and the idea is that in case of a reset or loss of power not losing a cumulative value that is saved during the execution of the program.

Thank you.

Julian.

Hola @Julian_Farchi,

Por el momento no es posible recuperar el valor directamente desde el servidor de Thinger, aún no está disponible esa funcionalidad, pero no tardará en llegar =D.

Por el momento, se me ocurren dos cosas que podrías hacer: La primera es almacenar el valor en la memoria flash del dispositivo usando la librería eeprom.h o mediante la memoria SPIFFS del WeMos, te dejo un ejemplo de código en el que puedes ver cómo hacerlo:

#include "FS.h"

void setup() {
  Serial.begin(115200);

  // always use this to "mount" the filesystem
  bool result = SPIFFS.begin();
  Serial.println("SPIFFS opened: " + result);

  // this opens the file "f.txt" in read-mode
  File f = SPIFFS.open("/f.txt", "r");
  
  if (!f) {
    Serial.println("File doesn't exist yet. Creating it");

    // open the file in write mode
    File f = SPIFFS.open("/f.txt", "w");
    if (!f) {
      Serial.println("file creation failed");
    }
    // now write two lines in key/value style with  end-of-line characters
    f.println("ssid=abc");
    f.println("password=123455secret");
  } else {
    // we could open the file
    while(f.available()) {
      //Lets read line by line from the file
      String line = f.readStringUntil('\n');
      Serial.println(line);
    }

  }
  f.close();
}

void loop() {
  // nothing to do for now, this is just a simple test

}


Otra opción, que no he probado nunca pero es viable, es crear un access point con permisos de acceso al data bucket y utilizar un cliente en el dispositivo para recuperar el JSON completo desde el data bucket mediante una http request como esta:

https://api.thinger.io/v1/users/jt/buckets/SensePoint/data?items=1&max_ts=0&sort=desc&authorization=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJEYXNoYm9hcmRfREVNTyIsInVzciI6Imp0In0.y_cwNQqIak5oQQhElcmO0hEYKEodds3UB8SHW7Rlmko

Al solicitarla, el servidor devuelve el siguiente JSON:
[{“ts”:1532878930886.0,“val”:{“batery”:3416.0,“humidity”:36.4385,“temperature”:27.8396}}]

Solo sería necesario recorrerlo para extraer la variable que quieres. Esta idea me gusta, quizá podríamos hacer un tutorial!!

Un saludo!

Si es una variable que cambia con el tiempo, no es recomendable guardarla en la EEPROM, ya que tiene un numero establecido de veces que puede ser escrita (cerca de 10k veces), al llegar a ese límite la memoria queda inservible, lo que yo particularmente sugiero guardar en eeprom es la configuración, ya que no se cambia frecuentemente :wink:

Me gusta la idea de consultar el ultimo dato del contenedor mediante un http request

En primer lugar, gracias por las ideas y comentarios.
A la primer opción ya la tenia descartada justamente por lo que comenta @ega, así que imaginaba algo como lo que propusiste como segunda, pero no tenia idea (y sinceramente aún no tengo) de como encararlo… realmente mi conocimiento sobre este tema es menos que básico. Ya con esta info me pondré a leer un poco y ver que sale.

Saludos!

Yo leí un poco acerca de como hacer la solicitud, pero honestamente lo que no tengo idea es como asignar las variables desde el bloque de datos recibido.

Voy a intentar hacer la consulta desde el micro y si logro hacerla posteo el código.

Logré visualizar datos en la consola serial

Hice la prueba con un NodeMCU y el sketch de ejemplo de thinger.io

Hay que incluir la libreria

#include <ESP8266HTTPClient.h>

El código para la consulta es el siguiente

  if (WiFi.status() == WL_CONNECTED) { //Check WiFi connection status
 
    HTTPClient http;  //Declare an object of class HTTPClient
 
    http.begin("http://api.thinger.io/v1/users/jt/buckets/SensePoint/data?items=1&max_ts=0&sort=desc&authorization=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJEYXNoYm9hcmRfREVNTyIsInVzciI6Imp0In0.y_cwNQqIak5oQQhElcmO0hEYKEodds3UB8SHW7Rlmko");  //Specify request destination
    int httpCode = http.GET();                                                                  //Send the request
 
    if (httpCode > 0) { //Check the returning code
 
      String payload = http.getString();   //Get the request response payload
      Serial.println(payload);                     //Print the response payload
 
    }
 
    http.end();   //Close connection
  }

Y en la consola serial se observa

[{“ts”:1533007988905.0,“val”:{“batery”:3389.0,“humidity”:35.2483,“temperature”:27.7216}}]
[{“ts”:1533007988905.0,“val”:{“batery”:3389.0,“humidity”:35.2483,“temperature”:27.7216}}]
[{“ts”:1533007988905.0,“val”:{“batery”:3389.0,“humidity”:35.2483,“temperature”:27.7216}}]
[{“ts”:1533007988905.0,“val”:{“batery”:3389.0,“humidity”:35.2483,“temperature”:27.7216}}]
[{“ts”:1533007988905.0,“val”:{“batery”:3389.0,“humidity”:35.2483,“temperature”:27.7216}}]
[{“ts”:1533007988905.0,“val”:{“batery”:3389.0,“humidity”:35.2483,“temperature”:27.7216}}]
[{“ts”:1533007988905.0,“val”:{“batery”:3389.0,“humidity”:35.2483,“temperature”:27.7216}}]
[{“ts”:1533007988905.0,“val”:{“batery”:3389.0,“humidity”:35.2483,“temperature”:27.7216}}]
[{“ts”:1533007988905.0,“val”:{“batery”:3389.0,“humidity”:35.2483,“temperature”:27.7216}}]
[{“ts”:1533007988905.0,“val”:{“batery”:3389.0,“humidity”:35.2483,“temperature”:27.7216}}]
[{“ts”:1533007988905.0,“val”:{“batery”:3389.0,“humidity”:35.2483,“temperature”:27.7216}}]

Pero no sé cómo aparear los datos recibidos con las variables en el microcontrolador

2 Likes

Que grande @ega!! me apunto tu código.

Por el tema de la EEPROM, no os preocupéis, en realidad el Weemos utiliza una memoria flash, que también envejece pero no tan rápido.

un saludo!!

1 Like

Genial! :wink:

El dato devuelto por la plataforma está codificado en JSON. Se puede utilizar cualquier librería de Arduino para ello. En este caso devuelve un array de un único elemento (ya que se especifica items=1). Dentro contiene un objeto con el timestamp en milisegundos, y el valor que hay almacenando.

Saludos.

Ok, gracias Alvaro, no sé por qué pensaba hacerlo directamente de alguna forma con thinger, pensaba por ejemplo como se hace el llamado entre dispositivos, que se aparean ambos “thing”, pero leí por encima acerca de lo que comentas y no se ve difícil de verdad, (incluso me parece súper útil para api’s de otros servicios desde el microcontrolador), si logro hacerlo publico igualmente el codigo y si tengo tiempo hago el “how to” en inglés :wink:

Saludos

1 Like

Muchas gracias por la asistencia, con esta información pude resolver la situación. Con respecto a las librerías para trabajo con datos tipo JSON, he probado 2, pero para mi caso puntual me resultó mas practico hacer el tratamiento de la cadena devuelta mediante las funciones generales para operaciones con strings de arduino.

Ahora, solo por curiosidad y para intentar entender por completo, después de leer esto:

me queda la duda sobre de donde sale la URL a la cual hacer el pedido de datos, hay alguna documentacion disponible para consultar? yo para acceder a mi data bucket tomé como base lo puesto en el ejemplo y reemplacé el nombre de usuario, nombre del data bucket y autorización, todo esto sin crear el ningún access point…

Enhorabuena!

Podrías compartir cómo lograste extraer las variables de la cadena? Yo he intentado con algunas librerías JSON pero igualmente sin éxito.

El acceso al bucket no está documentado oficialmente, yo las consultas que he hecho ha sido trasteando por mi parte con algunos enlaces que he visto en el foro y un poco de ensayo y error.

Saludos

Aca va el detalle de como resolví la cuestión:

El texto de que devuelve mi consulta es el siguiente:

[{“ts”:1531188898077.0,“val”:{“sensor1”:15.5,“sensor2”:16.625,“sensor3”:15.6875}}]

Como se puede ver, en la respuesta está la timestamp y los valores leidos de 3 sensores.

Ahora, supongamos que la variable que quiero recuperar (o mandar por el puerto serie) es la correspondiente al sensor N°1; el código que usé fue el siguiente:

Serial.println (payload.substring(((payload.indexOf("sensor1", ((payload.indexOf("sensor1")))))+9),(payload.indexOf(",", ((payload.indexOf("sensor1")))))));

payload es la variable que guarda la cadena devuelta por la consulta

Esta es la idea de lo que hace el resto:

  1. buscar en que n° de caracter (o indice) de la cadena comienza el “nombre” del sensor del que se busca obtener el valor, en este caso “sensor1”. Esto lo hace lo hace la función indexOf() con la cadena buscada como argumento.

  2. tomando como base el indice obtenido en el punto anterior, le suma 9 (que es la longitud de la cadena “sensor1” incluidas las comillas, y desde esa posición busca el indice de la primer “,” (coma) que aparezca. Nuevamente la funcion indexOf() esta vez con dos argumentos, el primero es desde que indice empezar a buscar, el y el segundo el caracter buscado.

  3. con estos 2 datos ya sabemos la posición dentro de la cadena en la que se encuentra nuestra variable, y usamos la función substring(a+9,b) para recuperar el valor. a y b son los indices obtenidos en los pasos 1 y 2.

Después habrá que ver si el valor es un decimal y hace falta reemplazar puntos por comas o algo por el estilo antes de poder procesarlo según corresponda…

No es la explicación mas clara del mundo, pero creo que se entiende.

Julian.

Se entiende perfectamente, funcionó sin problemas.

Pienso que no hace falta reemplazar puntos por comas, con la función toFloat() o toInt() (en el caso que aplique cada una), debería funcionar sin problema

float sensor1 = payloadSensor1.toFloat();

Donde payloadSensor1 es el string donde se guarda el valor de la variable extraída por el método que expones.

Gracias y saludos!