This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm whether you accept or reject these cookies being set.

A cookie will be stored in your browser regardless of choice to prevent you being asked this question again. You will be able to change your cookie settings at any time using the link in the footer.

  • 1 voto(s) - 5 Media
  • 1
  • 2
  • 3
  • 4
  • 5
Problema, no muestra decimales en thingspeak
#1
Hola! llevo un tiempo aprendiendo a hacer proyectitos con arduino y la verdad es que es un vicio, no hago más que comprar sensores y complementos. Y este foro me ha ayudado mucho a ir avanzando.
Últimamente estoy haciendo pruebas con NodeMcu, que para lo que quiero es perfecto, medir datos de temperatura, humedad y CO2, y enviarlos a thingspeak, para poder visualizarlos y descargar en csv.
Quería consultaros un problema que tengo y que no soy capaz de solucionar y es que los datos en thingspeak se muestran sin decimales, mientras que en el monitor serie de Arduino IDE se muestran con dos decimales (sensor DHT22). No sé donde está el error si en el envío de los datos o en la configuración en thingspeak, ¿me podéis ayudar?
Muchas gracias!
  Responder
#2
Si no pones el código del arduino... poco podemos hacer. El método de escritura de la librería de Thingspeak acepta determinados tipos de dato y no se que estarás enviando. El Serial.print del arduino contempla todos los tipos de datos como floats, strings, ints... etc y es normal que te lo muestre correctamente.

Lo dicho, expón tu código o poco podremos hacer.
  Responder
#3
Pues tienes toda la razón Shellmer.
Ahí va el código.

Código:
#include "DHT.h"
#include <ThingSpeak.h>
#include <ESP8266WiFi.h>          //https://github.com/esp8266/Arduino

//needed for library
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>         //https://github.com/tzapu/WiFiManager

#define DHTPIN 2     // what digital pin we're connected to
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
DHT dht(DHTPIN, DHTTYPE);

WiFiClient  client;
unsigned long myChannelNumber = 295726;
const char* myWriteAPIKey = "miApiKeydeescritura";

void setup() {
   // put your setup code here, to run once:
   Serial.begin(115200);
   Serial.println("DHTxx test!");
 
   //WiFiManager
   //Local intialization. Once its business is done, there is no need to keep it around
   WiFiManager wifiManager;
   //reset saved settings: quitar comentarios (//) la linea de abajo pararesetear las wifis guardadas
   //wifiManager.resetSettings();
   
   //set custom ip for portal
   //wifiManager.setAPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0));

   //fetches ssid and pass from eeprom and tries to connect
   //if it does not connect it starts an access point with the specified name
   //here  "AutoConnectAP"
   //and goes into a blocking loop awaiting configuration
   wifiManager.autoConnect("AutoConnectAP");
   //or use this for auto generated name ESP + ChipID
   //wifiManager.autoConnect();

   
   //if you get here you have connected to the WiFi
   Serial.println("connected...yeey :)");

 ThingSpeak.begin(client);
 dht.begin();  
}

void loop() {
 // Wait a few seconds between measurements.
 delay(56000);

 // Reading temperature or humidity takes about 250 milliseconds!
 // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
 float h = dht.readHumidity();
 // Read temperature as Celsius (the default)
 float t = dht.readTemperature();

 // Check if any reads failed and exit early (to try again).
 if (isnan(h) || isnan(t)) {
   Serial.println("Failed to read from DHT sensor!");
   return;
 }

 // Compute heat index in Celsius (isFahreheit = false)
 float hic = dht.computeHeatIndex(t, h, false);

 Serial.print("Temperatura:");
 Serial.print(t);
 Serial.print(" ");
 Serial.print("Humedad:");
 Serial.print(h);
 Serial.print(" ");
 Serial.print("Sensacion_termica:");
 Serial.println(hic);

ThingSpeak.setField(1,(int)t);
ThingSpeak.setField(2,(int)h);
ThingSpeak.setField(3,(int)hic);
ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
 
}
  Responder
#4
Tu problema es que antes de enviar los datos a ThingSpeak los estas convirtiendo a int, es decir aun entero, haciendo esto, eliminas los decimales y no los envias...

Esto esta mal
Código:
ThingSpeak.setField(1,(int)t);
ThingSpeak.setField(2,(int)h);
ThingSpeak.setField(3,(int)hic);

Esto deberia ser asi:
Código:
ThingSpeak.setField(1,t);
ThingSpeak.setField(2,h);
ThingSpeak.setField(3,hic);

Estas utilizando el constructor de int en lugar del de float, revisando la libreria veo que puedes asignar un float directamente... no se por que has realizado una conversión... no deberia darte error.
  Responder
#5
Genial!!! Muchas gracias, ya me funciona perfecto.
Copié esa parte del código y no sabía que significaba el (int).
Muchísimas gracias Shellmer.
  Responder
#6
Cuando pones un tipo de dato entre parentesis antes de una variable, lo que haces es hacer un "cast", en cristiano, realizas una conversión de tipo. Esto es interesante pues a veces tienes funciones en las que te interesa cargarte los decimales de una variable, o bien convertir un numero flotante en un entero porque la libreria que utilizas no admite floats.. .etc, hay muchas aplicaciones y es muy util.

Para que lo entiendas, esto funciona asi:


Código:
float num1 = 5.54;
int num2 = (int) num1;
num2 va a valer 5


Código:
int num1 = 5;
float num2 = (float) num1;
num2 va a valer 5.0 (como ves, tiene decimales)
Realmente, en este caso no haría ni falta hacer lo de (float) pues se almacenará igualmente un 5.0 en la variable al hacer la asignación ya que estamos guardando el valor de un entero en un flotante...



Esto es útil a veces, pues es necesario para realizar divisiones exactas y que el microcontrolador no asuma una división de entero entre entero (lo que da un entero), es decir:

Código:
float num1 = 5 / 2
num1 valdrá 2 debido a que esta realizando una división de enteros...

Lo correcto seria esto:
Código:
float num1 = (float) 5 / 2;

o...

Código:
float num1 = 5 / (float) 2;

Lo que daría 2.5 de resultado en num1

Este mismo resultado lo puedes obtener haciendo lo siguiente:

Código:
float num1 = 5.0 / 2;
De este modo, al poner 5.0 ya tenemos un float incluido en la operación, y el resultado va a ser un float.

Resumiendo... para hacer una división que de resultado en decimal, uno de los números divididos debe ser a la fuerza un float, y así puedes convertir un entero a un float de forma muy sencilla. Esta es una de las mayores aplicaciones de la conversión, pero hay muchas más.




Por cierto, como dato extra, estas haciendo una lectura cada 56 segundos, que sepas que puedes enviar datos a ThingSpeak cada 15 segundos como máximo, por si alguna vez se te ocurre mandar más cosas o hacer varios envios seguidos, que sepas que no te va a dejar hacerlo, cada envio debe estar espaciado por 15 segundos como mínimo. Si quieres que tu temperatura sea lo más en tiempo real posible... pon un delay de 20 segundos o así y listo.
  Responder
#7
Muy buena la explicación, esto es un mundo (sobretodo para mi que no tengo nada que ver con la programación) y poco a poco voy aprendiendo.

Una pregunta, ¿se puede limitar desde el código el número de decimales que quieres enviar?

En este caso en el cálculo de la sensación térmica (hic), hace una operación que genera muchos decimales en thingspeak, no me resulta ningún problema ya que se puede limitar los decimales en cada tabla con la opción Rounding, pero también parece innecesario enviar tanta información.

No había visto la última parte de tu mensaje

Cita:Por cierto, como dato extra, estas haciendo una lectura cada 56 segundos, que sepas que puedes enviar datos a ThingSpeak cada 15 segundos como máximo, por si alguna vez se te ocurre mandar más cosas o hacer varios envios seguidos, que sepas que no te va a dejar hacerlo, cada envío debe estar espaciado por 15 segundos como mínimo. Si quieres que tu temperatura sea lo más en tiempo real posible... pon un delay de 20 segundos o así y listo.

Por ahora lo tengo así para obtener datos cada minuto y comparar los resultados con otro sistema de monitorización que tengo, que recoge datos con esa frecuencia. Son 56 segundos, porque he visto que tarda unos 4 segundos en gestionar el dato. Lo ideal sería que lo hiciera cada minuto exacto pero para mi eso ya son palabras mayores.
  Responder
#8
La libreria de ThingSpeak convierte el numero decimal a una cadena de caracteres... hay maneras de cortar el numero de decimales, pero sin tocar la libreria directamente no creo que puedas hacer nada, básicamente porque si tu por ejemplo pones:

Código:
ThingSpeak.setField(1,t);
Y por ejemplo t = 22.0567386843

Y tu con otras funciones la recortas a 22.05 es muy probable que al pasar por la función de setField se te genere una cadena de caracteres que ponga "22.05000"


Por lo que he visto en la librería, utiliza una función que recorta el numero a 5 decimales, y sin editar directamente la librería, creo que te hará eso.
La función que utiliza es "convertFloatToChar" y esta incluida dentro de la librería, si quisieses recortar lo que se envía, deberías editarla.



Para hacer que te gestione eso cada minuto exacto, y digo exacto del todo necesitas utilizar un timer (Aunque si me dices que llevas poco programando, mejor dejalo para más adelante), lo que si deberías aprender a usar la función millis() para ejecutar la espera en lugar del delay(), el millis lo gestiona el timer0 y debería ser lo suficientemente exacto para tu propósito. No es difícil y es un básico en la programación con arduino.
  Responder
#9
Cita:Por lo que he visto en la librería, utiliza una función que recorta el numero a 5 decimales, y sin editar directamente la librería, creo que te hará eso.
La función que utiliza es "convertFloatToChar" y esta incluida dentro de la librería, si quisieses recortar lo que se envía, deberías editarla.

Hecho! He cambiado el 5 por el 2 en la librería y me muestra los dos decimales, no necesito más! Así supongo que cuando no disponga de una wifi en el edificio y tenga que generar una a través de wifidirect, tendré menos gasto de datos.

Cita:Para hacer que te gestione eso cada minuto exacto, y digo exacto del todo necesitas utilizar un timer (Aunque si me dices que llevas poco programando, mejor dejalo para más adelante), lo que si deberías aprender a usar la función millis() para ejecutar la espera en lugar del delay(), el millis lo gestiona el timer0 y debería ser lo suficientemente exacto para tu propósito. No es difícil y es un básico en la programación con arduino.

Me lo apunto para aprenderlo y aplicarlo en mi código.
Muchas gracias de nuevo!
  Responder
#10
Bueno, ya has hecho mucho más que otros... mucha gente no se atreve a modificar las librerías, y a veces, es la forma más rápida y sencilla de arreglar las cosas y obtener lo que queremos, ahora bien, recuerda que esa librería la has modificado y que si pasas ese código a un portátil por ejemplo, deberías antes copiar la librería modificada y instalarla a mano en el directorio de librerías... no seria la primera vez que yo modifico una librería y que no me acuerdo y luego me vuelvo loco al compilar y ver que no va bien hasta que recuerdo que he modificado la librería en el otro ordenador.

Eso me paso con la libreria del DHT, esa que usas del sensor por ejemplo, la modifique para que no tardase 250ms en leer (tenia que leer 12 sensores de temperatura, se eternizaba y no me dejaba tiempo para actualizar otras cosas... como una pantalla LCD... y me paso tambien con la de la pantalla LCD, que cambie filas por columnas y luego no me iba en otro ordenador jajaja.
  Responder
#11
He hecho una copia del archivo original.
Conociéndome va a ser muy probable que me olvide, ya que estoy aprendiendo muchas cosas a lavez. Voy a hacerme una pequeña guía de lo que voy haciendo, si no va a ser imposible acordarme de todo, y cada vez se añaden más cosas que aprender, por ejemplo ahora los millis Gran sonrisa
  Responder
#12
Me ha picado la curiosidad de mejorar el tiempo entre lecturas y he intentado usar la función millis (timer no me he atrevido por lo que has puesto).
La verdad es que me funciona, pero no lo hace cada minuto, al igual que con delay tarda 4-5 segundos más.
Este es el código que estoy utilizando.
Código:
#include "DHT.h"
#include <ThingSpeak.h>
#include <ESP8266WiFi.h>          //https://github.com/esp8266/Arduino

//needed for library
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>         //https://github.com/tzapu/WiFiManager

#define DHTPIN 2     // what digital pin we're connected to
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
DHT dht(DHTPIN, DHTTYPE);

WiFiClient  client;
unsigned long myChannelNumber = 295726;
const char* myWriteAPIKey = "yapikeywriter";

void setup() {
   // put your setup code here, to run once:
   Serial.begin(115200);
   Serial.println("DHTxx test!");
 
   //WiFiManager
   //Local intialization. Once its business is done, there is no need to keep it around
   WiFiManager wifiManager;
   //reset saved settings: quitar comentarios (//) la linea de abajo pararesetear las wifis guardadas
   //wifiManager.resetSettings();

   wifiManager.autoConnect("AutoConnectAP");

   Serial.println("connected...yeey :)");

 ThingSpeak.begin(client);
 dht.begin();  
}
long tiempoUltimaLectura=0;; //Para guardar el tiempo de la última lectura
void loop() {
      // Wait a few seconds between measurements.
      // delay(56000);
//---------Lectura del Sensor--------------------------
 if(millis()-tiempoUltimaLectura>60000)
 {  

 // Reading temperature or humidity takes about 250 milliseconds!
 // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
 float h = dht.readHumidity();
 float t = dht.readTemperature();

 // Check if any reads failed and exit early (to try again).
 if (isnan(h) || isnan(t)) {
   Serial.println("Failed to read from DHT sensor!");
   return;
 }

 // Compute heat index in Celsius (isFahreheit = false)
 float hic = dht.computeHeatIndex(t, h, false);
 
     //--------Enviamos las lecturas por el puerto serial-------------
 Serial.print("Temperatura:");
 Serial.print(t);
 Serial.print(" ");
 Serial.print("Humedad:");
 Serial.print(h);
 Serial.print(" ");
 Serial.print("Sensacion_termica:");
 Serial.println(hic);

     //--------Enviamos las lecturas a Thingspeak-------------
 ThingSpeak.setField(1,t);
 ThingSpeak.setField(2,h);
 ThingSpeak.setField(3,hic);
 ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);

tiempoUltimaLectura=millis(); //actualizamos el tiempo de la última lectura
 }
 //----Fin de la lectura---------------------------
}
  Responder
#13
Pon lo de tiempoUltimaLectura=millis(); como primera instrucción una vez entras en el if.

Lo que te esta pasando es que estas actualizando el tiempo de ultima lectura tras haber esperado por que el sensor lea y los datos se envíen... y por lo que comentabas tardaba 4 segundos en hacerlo todo....

Si lo pones como primera instrucción, seguirá tardando 4 segundos pero lo que hará es actualizarse el valor, pasaran 4 segundos y 56 segundos después volverá a cumplirse la condición y entrara de nuevo.




Y esto como dato aparte, realmente no te causará ningún problema dejar el código tal y como lo tienes, pero es interesante que lo sepas:

Ese long que declaras: "tiempoUltimaLectura" declaralo como "unsigned long" en lugar de "long", ya que los millis están guardados como unsigned long... Millis() lo que hace es darte la cantidad de milisegundos transcurridos desde que el microcontrolador ha arrancado.
Añadir el "unsigned" a una variable antes de declararla significa que duplicas el tamaño máximo de la variable al prescindir del bit que indica el signo... en l caso del long asi puedes almacenar un valor de entre 0 y 4,294,967,295 (El long a secas permite almacenar de -2,147,483,648 a 2,147,483,647, ten en cuenta que nunca va a haber tiempo negativo así que es innecesario ese bit)

En milisegundos, 4,294,967,295 equivale a 49.71 días... vamos, que esa variable llegaría a su máximo valor al cabo de casi 50 días, y en ese momento, al superarlo volvería a 0.
  Responder
#14
Probado! Lo he dejado toda la noche tomando datos cambiando lo de tiempoUltimaLectura=millis(); como primera instrucción y ya me toma datos cada minuto. 
Después pruebo poner "unsigned long" y pongo el código por si alguien le sirve tenerlo completo.
Muchas gracias de nuevo por tu interés Shellmer.
  Responder
#15
Ahí va el código final con la colaboración de Shellmer.
Lo uso en un NodeMCU v3 y con un sensor DHT22.
Lo que hace es conectarse a una red wifi (si no la tiene almacenada, se configura conectándose a la wifi que crea el dispositivo), lee los datos de temperatura y humedad del sensor DHT22 cada minuto y los envía a una cuenta de thingspeak.

Código:
#include "DHT.h"
#include <ThingSpeak.h>
#include <ESP8266WiFi.h>          //https://github.com/esp8266/Arduino
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>         //https://github.com/tzapu/WiFiManager

#define DHTPIN 2     // what digital pin we're connected to
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
DHT dht(DHTPIN, DHTTYPE);

WiFiClient  client;
unsigned long myChannelNumber = xxxxxx;
const char* myWriteAPIKey = "xxxxxxxxxxxxxxxxxx";

void setup() {
   Serial.begin(115200);
   Serial.println("DHT test!");
 
   //WiFiManager
   //Local intialization. Once its business is done, there is no need to keep it around
   WiFiManager wifiManager;
   //reset saved settings: quitar comentarios de la linea de abajo para resetear la wifi guardada
   //wifiManager.resetSettings();
   
   //set custom ip for portal
   //wifiManager.setAPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0));

   //fetches ssid and pass from eeprom and tries to connect
   //if it does not connect it starts an access point with the specified name
   //here  "AutoConnectAP"
   //and goes into a blocking loop awaiting configuration
   wifiManager.autoConnect("AutoConnectAP");
   //or use this for auto generated name ESP + ChipID
   //wifiManager.autoConnect();

   //if you get here you have connected to the WiFi
   Serial.println("conectado! :)");

 ThingSpeak.begin(client);
 dht.begin();  
 }
unsigned long tiempoUltimaLectura=0;; //Para guardar el tiempo de la última lectura
void loop() {

   //---------Lectura del Sensor--------------------------
   // Wait a few seconds between measurements.
 if(millis()-tiempoUltimaLectura>60000)  //Tiempo entre lecturas (en este caso 60 segundos)
 {  
 tiempoUltimaLectura=millis(); //actualizamos el tiempo de la última lectura

 // Reading temperature or humidity takes about 250 milliseconds!
 // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
 float h = dht.readHumidity();
 float t = dht.readTemperature();

 // Check if any reads failed and exit early (to try again).
 if (isnan(h) || isnan(t)) {
   Serial.println("Fallo de lectura desde el sensor DHT!");
   return;
 }

 // Compute heat index in Celsius (isFahreheit = false)
 float hic = dht.computeHeatIndex(t, h, false);
 
   //--------Enviamos las lecturas por el puerto serial-------------
 Serial.print("Temperatura:");
 Serial.print(t);
 Serial.print(" ");
 Serial.print("Humedad:");
 Serial.print(h);
 Serial.print(" ");
 Serial.print("Sensacion_termica:");
 Serial.println(hic);

   //--------Enviamos las lecturas a Thingspeak-------------
 ThingSpeak.setField(1,t);
 ThingSpeak.setField(2,h);
 ThingSpeak.setField(3,hic);
 ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);

 }
 //----Fin de la lectura---------------------------

}
  Responder


Posibles temas similares…
Tema Autor Respuestas Vistas Último mensaje
  Subir datos a ubidots y thingspeak desde un dispositivo. alejayo 5 2,775 16-08-2017, 11:30 AM
Último mensaje: alejayo
  Como recortar decimales Ergon 4 2,603 08-07-2013, 11:18 PM
Último mensaje: DiegoLale