Calificación:
  • 0 voto(s) - 0 Media
  • 1
  • 2
  • 3
  • 4
  • 5
Fusionar dos sketch en uno (código arduino)
#1
Hola buenas, saludos a todos y todas, voy a explicar cual es el proyecto que llevo en mente y a ver si alguien que controle de programación me puede dar una solución, ya que yo me dedico a robar código, pero a la hora de escribirlo ya me cuesta un poco.

El tema es que quiero poder hacer una lectura de temperatura de una habitación y poder encender o apagar una calefacción desde el móvil android, para ello quiero usar "solamente un ESP8266 ESP-01" nada más.

1º - El tema es que ya tengo el código configurado del módulo ESP8266 para que me lea un sensor de temperatura LM35 en la patilla gpio0 y que la información me la mande a la web thingspeak, te bajas luego la aplicación móvil y ya tienes un registro de temperatura de donde quieras conectado a tu wifi y pudiendo verlo con el móvil desde donde sea, hasta aquí perfecto, sin problemas.

2º - Con el código del punto anterior lo que hago es recoger datos y enviarlos a una web, pero lo que quiero ahora es poder "enviar" desde el teléfono móvil una señal para activar la patilla gpio2 y de esta forma activar o desactivar la calefacción.

Bien, los dos puntos por separado los tengo resueltos con sus respectivos códigos, el punto primero además de leer la temperatura y enviarla a thingspeak también me gestiona la temperatura de la habitación, actúa como termostato. 

Teniendo en cuenta los costos y demás, la verdad es que si uso dos módulos ESP8266 no me va a salir por mas de 5 euros, pero claro, pudiendo compactar todo en uno, pues eso que me ahorro luego en alimentar el circuito, menos engorros con IP´s y demás. Porque he pensado en usar un módulo ESP8266 para enviar la temperatura y usar otro módulo para mover el relé que actuará sobre la caldera, pero como soy cabezón, quiero hacerlo con tan sólo un, pero ahí es donde choco.

Voy a adjuntar los sketchs que estoy usando por separado, el tema sería poder unir los dos en uno, pero me es imposible por mis carencias en programación.

Sketch que lee la temperatura del sensor LM35 y la envía a thingspeak:

Código:
#include <ThingSpeak.h>

#include<ESP8266WiFi.h>

String apiKey = "xxxxxxxxxxxxxx";
const char* ssid = "ONOABAB";
const char* password = "xxxxxxxx";
const char* server = "api.thingspeak.com";
float temp= 0;

int analog=0;
const int pinled = 2;


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

void setup() {

  // prepare GPIO2
pinMode(1, OUTPUT);
digitalWrite(1, 0);

pinMode(pinled, OUTPUT);  

// put your setup code here, to run once:
Serial.begin(9600);
delay(10);
WiFi.begin(ssid, password);
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while( WiFi.status()!=WL_CONNECTED){
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
ThingSpeak.begin(client);
}

void loop() {


// put your main code here, to run repeatedly:
analog=analogRead(0);



float temp= (5.0 * analog * 100.0)/1024.0;

    if (temp <=23)
    {
    digitalWrite(pinled, HIGH);
    }
    else
    {
    digitalWrite(pinled, LOW);
    }

Serial.print("Temperatura: ");

Serial.println(temp);
Serial.println("Enviando datos...");
Serial.println();
Serial.println("Midiendo temperatura....");
ThingSpeak.writeField(myChannelNumber, 1, temp, myWriteAPIKey);
delay(20000);
}

Sketch con el que, usando AppInventor envío un impulso a la patilla gpio0 del ESP8266:

Código:
#include <ESP8266WiFi.h>



const char* ssid = "xxxxxxx";

const char* password = "xxxxxx";



// Create an instance of the server

// specify the port to listen on as an argument

WiFiServer server(80);



void setup() {

Serial.begin(9600);

delay(10);



// prepare GPIO2

pinMode(2, OUTPUT);

digitalWrite(2, 0);



// Connect to WiFi network

Serial.println();

Serial.println();

Serial.print("Connecting to ");

Serial.println(ssid);



WiFi.begin(ssid, password);



while (WiFi.status() != WL_CONNECTED) {

  delay(500);

  Serial.print(".");

}

Serial.println("");

Serial.println("WiFi connected");



// Start the server

server.begin();

Serial.println("Server started");



// Print the IP address

Serial.println(WiFi.localIP());

}



void loop() {

// Check if a client has connected

WiFiClient client = server.available();

if (!client) {

  return;

}



// Wait until the client sends some data

Serial.println("new client");

while(!client.available()){

  delay(1);

}



// Read the first line of the request

String req = client.readStringUntil('\r');

Serial.println(req);

client.flush();



// Match the request

int val;

if (req.indexOf("/gpio/0") != -1)

  val = 0;

else if (req.indexOf("/gpio/1") != -1)

  val = 1;

else {

  Serial.println("invalid request");

  client.stop();

  return;

}



// Set GPIO2 according to the request

digitalWrite(2, val);



client.flush();



// Prepare the response

String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\nGPIO is now ";

s += (val)?"high":"low";

s += "</html>\n";



// Send the response to the client

client.print(s);

delay(1);

Serial.println("Client disonnected");



// The client will actually be disconnected

// when the function returns and 'client' object is detroyed
}

Pues eso, lo que me gustaría es poder combinar los dos códigos en uno y conseguir leer los datos del LM35 y poder recibir un impulso en la patilla gpio0, pero todo en un sólo módulo ESP8266.





Quizás sea la cosa mas chorra del mundo, pero me es totalmente imposible hacerme una idea de como hacerlo, y os aseguro que lo he intentado con mil combinaciones, pero nada, también decir que sé que hay mas opciones, módulos ESP8266 más grandes y con mas opciones de programación, que puedo usar un arduino nano o UNO, etc etc.....el tema es que quiero hacerlo en plan "stand alone", usar un simple módulo ESP8266 ESP-01 para conseguir esto....



¿Alguna ayuda?


Mil gracias por vuestro tiempo.
Citar
#2
Código:
#include <ThingSpeak.h>
#include<ESP8266WiFi.h>

//Pon aqui los pines a los que esta conectado tu led y tu relé de la caldera
#define pinled 2
#define releCaldera 3

String apiKey = "xxxxxxxxxxxxxx";
const char* ssid = "ONOABAB";
const char* password = "xxxxxxxx";
const char* server = "api.thingspeak.com";

float temp= 0;
int analog=0;

WiFiClient client;
WiFiServer server(80);
unsigned long myChannelNumber = xxxxxx;
const char * myWriteAPIKey = "xxxxxxx";

unsigned long int anteriorRefreshTemperatura = 0;

void setup() {
 //¿? No se usa el pin 1 en ningun lado en ningun sketch, los pines 0 y 1 suelen ser los pines de comunicacion RX y TX, si no comunica, comentar estas dos lineas
 pinMode(1, OUTPUT);
 digitalWrite(1, 0);
 //

 //Relé de la caldera
 pinMode(releCaldera, OUTPUT);
 digitalWrite(releCalderareleCaldera, LOW);
 
 pinMode(pinled, OUTPUT);  

 //Iniciamos puerto serie
 Serial.begin(9600);
 delay(10);

 //Iniciamos el modulo wifi
 WiFi.begin(ssid, password);
 Serial.println();
 Serial.println();
 Serial.print("Connectandose a ");
 Serial.println(ssid);
 WiFi.begin(ssid, password);
 
 while( WiFi.status() != WL_CONNECTED){
   delay(500);
   Serial.print(".");
 }
 Serial.println("");
 Serial.println("WiFi connectado");
 
 ThingSpeak.begin(client);
 Serial.println("Cliente thingspeak iniciado");
 server.begin();
 Serial.print("Servidor iniciado, IP: ");
 Serial.println(WiFi.localIP());
}

void refreshTemperatura(){
 /* Si hemos ejecutado esta funcion hace más de 20 segundos
  * (O lo que sea, cambiar 20000 por el valor en milisegundos deseado)
  * se ejecutará lo de dentro, en caso contrario... no hará nada
  *
  * Lo hacemos asi para no complicar demasiado el código, si no seria
  * necesario hacer que el codigo se ejecutase lanzandose una interrupcion
  * cada 20 segundos, si funciona asi... asi es mas sencillo
 */
 if (millis() > anteriorRefreshTemperatura + 20000){
   anteriorRefreshTemperatura = millis();
   //Leemos la temperatura en el canal 0... A0??
   analog = analogRead(0);
   float temp= (5.0 * analog * 100.0)/1024.0;
   if (temp <=23){
     digitalWrite(pinled, HIGH);
   } else {
     digitalWrite(pinled, LOW);
   }
   
   Serial.print("Temperatura: ");
   Serial.println(temp);
   
   Serial.println("Enviando datos...");
   Serial.println();
   Serial.println("Midiendo temperatura....");
   //ThingSpeak.writeField(myChannelNumber, 1, temp, myWriteAPIKey);
 }
}

void loop() {
 //Lectura del sensor de temperatura
 refreshTemperatura();

 //Codigo servidor
 
 WiFiClient client = server.available();
 if (!client) { //Si no se ha conectado nadie, saltamos al inicio del codigo
   return;
 }
 Serial.println("Nuevo cliente conectado");
 while(!client.available()){
   //Esperamos hasta que el cliente haya solicitado o enviado datos
   delay(1);

   //De paso que estamos esperando al cliente... pues comprobamos  si hemos de actualizar la temperatura.
   refreshTemperatura();
 }

 // Read the first line of the request
 String req = client.readStringUntil('\r');
 Serial.println(req);
 client.flush();
 
 // Match the request
 int val;
 if (req.indexOf("/gpio/0") != -1){
   val = 0;
 } else if (req.indexOf("/gpio/1") != -1){
   val = 1;
 } else {
   Serial.println("peticion invalida");
   client.stop();
   return;
 }
 
 // Ponemos el pin a 0 o a 1, dependiendo de lo recibido
 digitalWrite(releCaldera, val);
 client.flush();
 
 // Preparamos respuesta
 String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\nGPIO is now ";
 s += (val)?"high":"low";
 s += "</html>\n";
 
 
 
 // Enviamos la respuesta al cliente
 client.print(s);
 delay(1);
 Serial.println("Cliente desconectado");
 
 /* El loop() se vuelve a ejecutar, y al volver a llamar 'WiFiClient client = server.available();'
  *  creamos un nuevo objeto cliente y por tanto, desconectamos a la fuerza al anterior cliente
 */
}

  • No he podido compilarlo, pues no tengo esas librerias
  • Tienes un trozo de código 'inutil' en el setup, lo he marcado con un comentario, por alguna razón pones el pin 1 como OUTPUT y no lo usas para nada en el programa... los pines 0 y 1 suelen ser los empleados para la comunicación serie en los arduino, supongo que en el ESP es igual, así que si no te comunica, comenta esas dos lineas
  • La lectura de temperatura se realiza cada 20 segundos, si quieres leer en un intervalo menor, debes cambiar el '20000' por el valor deseado en milisegundos
  • Este código de lectura de temperatura debería ejecutarse con una interrupción cada x tiempo si quisiésemos hacerlo bien del todo, ya que un microcontrolador no puede gestionar dos tareas al mismo tiempo, estoy habituado a los PICS de microchip en lugar de arduino, así que lo he hecho de otra forma, debería funcionar igualmente.
  • No te aseguro que funcione, básicamente porque no lo he podido compilar, carezco de esos módulos y ignoro si el ESP puede ejercer de cliente y de servidor web al mismo tiempo.

Por ultimo deberás revisar si tu relé se activa con un HIGH o un LOW, los reles en placa para arduino suelen activarse en 'LOW', quiza debas invertir la logica inicial en el siguiente fragmento:
Código:
 //Relé de la caldera
 pinMode(releCaldera, OUTPUT);
 digitalWrite(releCalderareleCaldera, LOW);
Y cambiarlo por:
Código:
 //Relé de la caldera
 pinMode(releCaldera, OUTPUT);
 digitalWrite(releCalderareleCaldera, HIGH);
Citar
#3
Hola, muchísimas gracias por tu tiempo.
La compilación me da múltiples fallos, el primero es que no puede haber un

WiFiClient client;
WiFiServer server(80);

Me dice que es incompatible, y a partir de ahí, haciendo alguna modificación me es imposible continuar por mi nivel pésimo de programación.

Lo del trozo de código inútil, perdona, estaba haciendo unas pruebas y me lo dejé por ahí en medio, es verdad, no vale para nada.

Y sí, el ESP puede trabajar de los dos modos, de cliente y de servidor.

Los dos sketchs que colgué, de manera individual funcionan correctamente, llevo unas cuantas horas dedicadas a buscar información por internet y no he encontrado nada en ningún idioma en el que alguien haga lo que pretendo, pero si por separado se puede hacer, entiendo que también se puede hacer todo en un mismo módulo ESP8266, el problema será el conflicto en cuanto a los servidores wifi................o vete a saber!!!!
Citar
#4
Código:
#include <ThingSpeak.h>
#include<ESP8266WiFi.h>

//Pon aqui los pines a los que esta conectado tu led y tu relé de la caldera
#define pinled 2
#define releCaldera 3

String apiKey = "xxxxxxxxxxxxxx";
const char* ssid = "ONOABAB";
const char* password = "xxxxxxxx";
const char* server = "api.thingspeak.com";
unsigned long myChannelNumber = 12345678;
const char * myWriteAPIKey = "xxxxxxx";

WiFiClient client;
WiFiServer servidor(80);

unsigned long int anteriorRefreshTemperatura = 0;
float temp= 0;
int analog=0;

void setup() {
//Relé de la caldera
pinMode(releCaldera, OUTPUT);
digitalWrite(releCaldera, LOW);

pinMode(pinled, OUTPUT);  

//Iniciamos puerto serie
Serial.begin(9600);
delay(10);

//Iniciamos el modulo wifi
WiFi.begin(ssid, password);
Serial.println();
Serial.println();
Serial.print("Connectandose a ");
Serial.println(ssid);
WiFi.begin(ssid, password);

while( WiFi.status() != WL_CONNECTED){
  delay(500);
  Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connectado");

ThingSpeak.begin(client);
Serial.println("Cliente thingspeak iniciado");
servidor.begin();
Serial.print("Servidor iniciado, IP: ");
Serial.println(WiFi.localIP());
}

void refreshTemperatura(){
/* Si hemos ejecutado esta funcion hace más de 20 segundos
 * (O lo que sea, cambiar 20000 por el valor en milisegundos deseado)
 * se ejecutará lo de dentro, en caso contrario... no hará nada
 *
 * Lo hacemos asi para no complicar demasiado el código, si no seria
 * necesario hacer que el codigo se ejecutase lanzandose una interrupcion
 * cada 20 segundos, si funciona asi... asi es mas sencillo
*/
if (millis() > anteriorRefreshTemperatura + 20000){
  anteriorRefreshTemperatura = millis();
  //Leemos la temperatura en el canal 0... A0??
  analog = analogRead(0);
  float temp= (5.0 * analog * 100.0)/1024.0;
  if (temp <=23){
    digitalWrite(pinled, HIGH);
  } else {
    digitalWrite(pinled, LOW);
  }
 
  Serial.print("Temperatura: ");
  Serial.println(temp);
 
  Serial.println("Enviando datos...");
  Serial.println();
  Serial.println("Midiendo temperatura....");
  ThingSpeak.writeField(myChannelNumber, 1, temp, myWriteAPIKey);
}
}

void loop() {
//Lectura del sensor de temperatura
refreshTemperatura();

//Codigo servidor

WiFiClient clienteDeServidor = servidor.available();
if (!clienteDeServidor) { //Si no se ha conectado nadie, saltamos al inicio del codigo
  return;
}
Serial.println("Nuevo cliente conectado");
while(!clienteDeServidor.available()){
  //Esperamos hasta que el cliente haya solicitado o enviado datos
  delay(1);

  //De paso que estamos esperando al cliente... pues comprobamos  si hemos de actualizar la temperatura.
  refreshTemperatura();
}

// Read the first line of the request
String req = clienteDeServidor.readStringUntil('\r');
Serial.println(req);
clienteDeServidor.flush();

// Match the request
int val;
if (req.indexOf("/gpio/0") != -1){
  val = 0;
} else if (req.indexOf("/gpio/1") != -1){
  val = 1;
} else {
  Serial.println("peticion invalida");
  clienteDeServidor.stop();
  return;
}

// Ponemos el pin a 0 o a 1, dependiendo de lo recibido
digitalWrite(releCaldera, val);
clienteDeServidor.flush();

// Preparamos respuesta
String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\nGPIO is now ";
s += (val)?"high":"low";
s += "</html>\n";



// Enviamos la respuesta al cliente
clienteDeServidor.print(s);
delay(1);
Serial.println("Cliente desconectado");

/* El loop() se vuelve a ejecutar, y al volver a llamar 'WiFiClient clienteDeServidor = servidor.available();'
 *  creamos un nuevo objeto cliente y por tanto, desconectamos a la fuerza al anterior cliente
*/
}

Este código ya compila, había conflictos en la declaración, tenias una cadena de caracteres que se llamaba 'server' y un WifiServer que se llamaba 'server', eso no puede hacerse, cada variable debe tener un nombre único o da fallo... he instalado las librerias y compilado, cuando unes códigos... a veces no se ve a simple vista lo redundante, es mejor compilar y ver los errores.
Por otro lado, tenias el 'unsigned long myChannelNumber = xxxxxx;' declarado con valor 'xxxxxxx', supongo que lo pasaste así para no dar tus datos, daba error de compilación pues un long no admite caracteres, solo números.

Deberás reconfigurar este codigo para especificar arriba tus pines de caldera y de led así como tus datos en esta sección de código:
Código:
//Pon aqui los pines a los que esta conectado tu led y tu relé de la caldera
#define pinled 2
#define releCaldera 3

String apiKey = "xxxxxxxxxxxxxx";
const char* ssid = "ONOABAB";
const char* password = "xxxxxxxx";
const char* server = "api.thingspeak.com";
unsigned long myChannelNumber = 12345678;
const char * myWriteAPIKey = "xxxxxxx";

Por ultimo, a la hora de realizar la lectura de temperatura lees el puerto '0', si te funciona... pues perfecto, generalmente los puertos analogicos se especifican con "A0", "A1"... etc, para no confundirlos con los puertos digitales, pero si te funciona, déjalo así, ya que la función de analogread ya sabe que el 0 especificado corresponde al "A0" analógico en lugar del puerto 0 digital.
Código:
analog = analogRead(0);
Citar
#5
LA MADRE QUE TE PARIÓ........................................

Si eres de Valencia te invito a comer!!!!

Llevo unas 30 horas acumuladas buscando esta información y no existe en internet, ni en blogs de la India, y ya sabes que allí son unos cracks...

El poder enviar datos de un sensor a, por ejemplo, thingspeak como es el casi y a la vez poder enviar una señal desde el móvil al ESP8266 para activar un relé, es algo que de momento no hay en la red, o yo no lo he encontrado.
Hay cientos de sitios que te explican como hacer una cosa o la otra, pero las dos a la vez ni de coña. Ahora mismo con un módulo ESP8266, un sensor de temperatura y un relé soy capaz de tener un termostato en casa controlado a través de la red por menos de 7 euros en total...bueno, ahora falta la caja que me imprimiré y reciclar un cargador para alimentar el circuito.

De nuevo, muchas gracias por tu ayuda, y te lo repito, si vives en Valencia o cerca estás invitado a comer en algún restaurante...
Citar
#6
Vivo en Galicia, va a ser dificil coincidir, con tu mensaje supongo que has cargado el código en el ESP y te ha funcionado... si es así, me alegro, pues como te he dicho, al no tener ningún ESP no he podido más que compilarlo y punto. Tampoco he usado en la vida un ode estos modulos... quiza vaya siendo hora de comprarme alguno para hacer alguna cacharrada.

Es habitual no encontrar información de muchas cosas... lo adecuado suele ser irse a mirar datasheets y si encuentras librerías... pues abrirlas y echarles un ojo por dentro... hay un dicho muy popular y que es muy cierto y es el siguiente: "A programar se aprende programando"... así que sigue así, haz pruebas y pruebas y nunca te marcharás sin aprender algo nuevo pese a tener problemas...

Suerte con ello.
Citar
#7
Hola buenas, sí sí, además a la primera, cambié los pines y a funcionaro, recibo datos en thingspeak y puedo enviar con la app de inventor una señal a un led, que en breve será a un relé y a funcionar, ahora desde el móvil puedo ver la temperatura y dependiendo de esta activar la caldera desde fuera de casa, una maravilla.

Galicia!!!!!bonita tierra, hace mucho que no subo por aquellos lugares, pero aun me acuerdo de un verano que estuve en una pueblín, Vidueira, en Orense, cerca de la única estación de esquí que tenéis.

Bueno pues muchas gracias por todo, y sí, te animo a que te hagas con unos cuantos ESP8266 y trastees con ellos, son algo divertido y puedes hacer multitud de cosas con ellos, para cualquier consulta ya sabes...

Un abrazo y muchas gracias.
Citar
#8
Hola buenas, vamos con otra duda.....adjunto el código que finalmente estoy usando, que por supuesto es casi el 100% de Shellmer:

Código:
#include <ThingSpeak.h>
#include<ESP8266WiFi.h>
#include <DHT.h>
#include <Adafruit_Sensor.h>

#define DHTTYPE DHT11

const int releCaldera = 2;
const int DHTpin = 0;

DHT dht(DHTpin, DHTTYPE);

IPAddress ip(192, 168, 1, xx);
IPAddress gateway(192, 168, 1, xx);
IPAddress subnet(255, 255, 255, 0);


String apiKey = "xxxxxxxxxxxxxxxxxx";
const char* ssid = "ONOABAB";
const char* password = "xxxxxxxxxxxxxxxx";
const char* server = "api.thingspeak.com";
unsigned long myChannelNumber = xxxxxxxxxxxxxx;
const char * myWriteAPIKey = "xxxxxxxxxxxx";

WiFiClient client;
WiFiServer servidor(80);

unsigned long int anteriorRefreshTemperatura = 0;
float temp= 0;


void setup() {
//Relé de la caldera
pinMode(releCaldera, OUTPUT);
digitalWrite(releCaldera, LOW);



//Iniciamos puerto serie
Serial.begin(9600);
delay(10);

//Iniciamos el modulo wifi
WiFi.begin(ssid, password);
Serial.println();
Serial.println();
Serial.print("Connectandose a ");
Serial.println(ssid);
WiFi.begin(ssid, password);

// Static IP Setup Info Here...
WiFi.config(ip, gateway, subnet);

while( WiFi.status() != WL_CONNECTED){
 delay(500);
 Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connectado");

ThingSpeak.begin(client);
Serial.println("Cliente thingspeak iniciado");
servidor.begin();
Serial.print("Servidor iniciado, IP: ");
Serial.println(WiFi.localIP());
}

void refreshTemperatura(){
/* Si hemos ejecutado esta funcion hace más de 20 segundos
* (O lo que sea, cambiar 20000 por el valor en milisegundos deseado)
* se ejecutará lo de dentro, en caso contrario... no hará nada
*
* Lo hacemos asi para no complicar demasiado el código, si no seria
* necesario hacer que el codigo se ejecutase lanzandose una interrupcion
* cada 20 segundos, si funciona asi... asi es mas sencillo
*/
if (millis() > anteriorRefreshTemperatura + 20000){
 anteriorRefreshTemperatura = millis();
 //Leemos la temperatura en el canal 0... A0??
 //analog = analogRead(0);
 float t = dht.readTemperature();
 float temp=t;
 //float temp= (5.0 * t * 100.0)/1024.0;
 if (temp <=23){
   digitalWrite(releCaldera, HIGH);
 } else {
   digitalWrite(releCaldera, LOW);
 }
 
 Serial.print("Temperatura: ");
 Serial.println(temp);
 
 Serial.println("Enviando datos...");
 Serial.println();
 Serial.println("Midiendo temperatura....");
 ThingSpeak.writeField(myChannelNumber, 1, temp, myWriteAPIKey);
}
}

void loop() {
//Lectura del sensor de temperatura
refreshTemperatura();

//Codigo servidor

WiFiClient clienteDeServidor = servidor.available();
if (!clienteDeServidor) { //Si no se ha conectado nadie, saltamos al inicio del codigo
 return;
}
Serial.println("Nuevo cliente conectado");
while(!clienteDeServidor.available()){
 //Esperamos hasta que el cliente haya solicitado o enviado datos
 delay(1);

 //De paso que estamos esperando al cliente... pues comprobamos  si hemos de actualizar la temperatura.
 refreshTemperatura();
}

// Read the first line of the request
String req = clienteDeServidor.readStringUntil('\r');
Serial.println(req);
clienteDeServidor.flush();

// Match the request
int val;
if (req.indexOf("/gpio/0") != -1){
 val = 0;
} else if (req.indexOf("/gpio/1") != -1){
 val = 1;
} else {
 Serial.println("peticion invalida");
 clienteDeServidor.stop();
 return;
}

// Ponemos el pin a 0 o a 1, dependiendo de lo recibido
digitalWrite(releCaldera, val);
clienteDeServidor.flush();

// Preparamos respuesta
String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\nGPIO is now ";
s += (val)?"high":"low";
s += "</html>\n";



// Enviamos la respuesta al cliente
clienteDeServidor.print(s);
delay(1);
Serial.println("Cliente desconectado");

/* El loop() se vuelve a ejecutar, y al volver a llamar 'WiFiClient clienteDeServidor = servidor.available();'
*  creamos un nuevo objeto cliente y por tanto, desconectamos a la fuerza al anterior cliente
*/
}


Gracias éste código consigo ver la temperatura en thingspeak (en mi móvil) y enviar desde mi móvil (mediante una app de inventor) un señal a un relé para que me active o desactive la caldera, todo funcionando perfectamente. Ahora lo que me gustaría es poder variar la temperatura desde el móvil. Como puedes observar en el programa mediante esta línea "if (temp <=23)" limito la temperatura a 23 grados, me gustaría poder enviar un rango de temperaturas desde el móvil al ESP, pero no sé como hacerlo.
Había pensado en crear una variable "temperaturaDeseada" y enviar desde el móvil, al igual que envío para activar o desactivar el relé una temperatura y que la coloque en la variable y así poder tener un termostato más eficaz, pero no sé como implementar el código.

Gracias de antemano.
Citar
#9
No habiendo trabajado nunca con ThingSpeak ni con nada de esto no se si podré ayudarte, lo que necesitas es enviar desde el ThingSpeak un valor "int" o un valor 'float', necesitaría saber que es lo que recibe el Arduino si envías esos valores... eso o bien si por ejemplo podrías enviarle algo tal que así "tempmax=22" y ver que es lo que recibes, sabiendo esto podrías detectar lo que estas enviando y hacer precisamente lo que has comentado... actualizar una variable llamada temperaturadeseada o temperatura máxima y listo.


Hay funciones para pasar cadenas de caracteres a valores numericos e incluso separar datos en un String, la cosa es que no se como va la APP de thingspeak y que es lo que recibes en el arduino si envías algo... actualmente tienes este segmento de codigo:

Código:
// Read the first line of the request
String req = clienteDeServidor.readStringUntil('\r');
Serial.println(req);
clienteDeServidor.flush();

// Match the request
int val;
if (req.indexOf("/gpio/0") != -1){
 val = 0;
} else if (req.indexOf("/gpio/1") != -1){
 val = 1;
} else {
 Serial.println("peticion invalida");
 clienteDeServidor.stop();
 return;
}

Si consiguieses enviar algo tal que así: "tempmax=22" el código para actualizar eso y suponiendo que puedas recibir ese texto tal cual seria así:

Código:
#include <ThingSpeak.h>
#include<ESP8266WiFi.h>
#include <DHT.h>


#define DHTTYPE DHT11

const int releCaldera = 2;
const int DHTpin = 0;

DHT dht(DHTpin, DHTTYPE);

IPAddress ip(192, 168, 1, 0);
IPAddress gateway(192, 168, 1, 0);
IPAddress subnet(255, 255, 255, 0);


String apiKey = "xxxxxxxxxxxxxxxxxx";
const char* ssid = "ONOABAB";
const char* password = "xxxxxxxxxxxxxxxx";
const char* server = "api.thingspeak.com";
unsigned long myChannelNumber = 12345678;
const char * myWriteAPIKey = "xxxxxxxxxxxx";

WiFiClient client;
WiFiServer servidor(80);

unsigned long int anteriorRefreshTemperatura = 0;
float temp= 0;
float tempmax = 99;
int calderaHabilitada;


void setup() {
//Relé de la caldera
pinMode(releCaldera, OUTPUT);
digitalWrite(releCaldera, LOW);



//Iniciamos puerto serie
Serial.begin(9600);
delay(10);

//Iniciamos el modulo wifi
WiFi.begin(ssid, password);
Serial.println();
Serial.println();
Serial.print("Connectandose a ");
Serial.println(ssid);
WiFi.begin(ssid, password);

// Static IP Setup Info Here...
WiFi.config(ip, gateway, subnet);

while( WiFi.status() != WL_CONNECTED){
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connectado");

ThingSpeak.begin(client);
Serial.println("Cliente thingspeak iniciado");
servidor.begin();
Serial.print("Servidor iniciado, IP: ");
Serial.println(WiFi.localIP());
}

void refreshTemperatura(){
/* Si hemos ejecutado esta funcion hace más de 20 segundos
* (O lo que sea, cambiar 20000 por el valor en milisegundos deseado)
* se ejecutará lo de dentro, en caso contrario... no hará nada
*
* Lo hacemos asi para no complicar demasiado el código, si no seria
* necesario hacer que el codigo se ejecutase lanzandose una interrupcion
* cada 20 segundos, si funciona asi... asi es mas sencillo
*/
if (millis() > anteriorRefreshTemperatura + 20000){
anteriorRefreshTemperatura = millis();
//Leemos la temperatura en el canal 0... A0??
//analog = analogRead(0);
float t = dht.readTemperature();
float temp=t;
//float temp= (5.0 * t * 100.0)/1024.0;
if (temp <= tempmax && calderaHabilitada == 1){ //Si la temperatura que hay es menor a la maxima y la caldera está habilitada...
   digitalWrite(releCaldera, HIGH);
} else {
   digitalWrite(releCaldera, LOW);
}

Serial.print("Temperatura: ");
Serial.println(temp);

Serial.println("Enviando datos...");
Serial.println();
Serial.println("Midiendo temperatura....");
ThingSpeak.writeField(myChannelNumber, 1, temp, myWriteAPIKey);
}
}

void loop() {
//Lectura del sensor de temperatura
refreshTemperatura();

//Codigo servidor

WiFiClient clienteDeServidor = servidor.available();
if (!clienteDeServidor) { //Si no se ha conectado nadie, saltamos al inicio del codigo
return;
}
Serial.println("Nuevo cliente conectado");
while(!clienteDeServidor.available()){
//Esperamos hasta que el cliente haya solicitado o enviado datos
delay(1);

//De paso que estamos esperando al cliente... pues comprobamos  si hemos de actualizar la temperatura.
refreshTemperatura();
}

// Read the first line of the request
String req = clienteDeServidor.readStringUntil('\r');
String strTempMax = "";
Serial.println(req);
clienteDeServidor.flush();
// Match the request

if (req.indexOf("/gpio/0") != -1){
calderaHabilitada = 0;
} else if (req.indexOf("/gpio/1") != -1){
calderaHabilitada = 1;
} else if (req.indexOf("tempmax") != -1){
   strTempMax = req;
   strTempMax.replace("tempmax=","");
   tempmax = strTempMax.toFloat();
} else {
Serial.println("peticion invalida");
clienteDeServidor.stop();
return;
}

// Ponemos el pin a 0 o a 1, dependiendo de lo recibido
//digitalWrite(releCaldera, calderaHabilitada); Esto te sobra... estas gestionando la temperatura arriba
clienteDeServidor.flush();

// Preparamos respuesta
String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\nGPIO is now ";
s += (calderaHabilitada)?"high":"low";
s += "</html>\n";



// Enviamos la respuesta al cliente
clienteDeServidor.print(s);
delay(1);
Serial.println("Cliente desconectado");

/* El loop() se vuelve a ejecutar, y al volver a llamar 'WiFiClient clienteDeServidor = servidor.available();'
*  creamos un nuevo objeto cliente y por tanto, desconectamos a la fuerza al anterior cliente
*/
}

Me he cargado un include que tenias por ahí que no me dejaba compilar y sobraba y también lo de que pongas el pin a 1 de la caldera si recibes un 1... no tiene sentido eso si estas encendiendola o apagandola si alcanzas o no X temperatura... ya que en caso de que se excediese la temperatura, a los 20 segundos, tras la siguiente actualización se te apagaría. En su lugar he convertido la variable en global y ahora mas bien seria una variable que le indica al programa si tiene permitido encender la caldera si hace falta...


Si esto te funcionase... (que no estoy seguro no sabiendo que recibes en la variable "req"), aun habría que mejorar el código pues no estamos teniendo en cuenta la histeresis de la temperatura... sin hacer que tenga histeresis podríamos estar encendiendo y apagando continuamente la caldera cuando la temperatura actual es muy próxima a la objetivo (Si es <= que 22.0º encendida, a los 22.10º apagada... creo que se aprecia el problema, ademas estos sensores no son 100% precisos y entre una lectura y otra puede variar la temperatura algo). Si funciona ya veremos eso luego...


Lo dicho.. intenta enviar con el ThingSpeak un texto que ponga "tempmax=22", sustituyendo el 22 por la temperatura maxima deseada y mira si funciona...
Citar
#10
Código:
if (temp -1 <=tempDeseada){
   digitalWrite(releCaldera, HIGH);
 }
  if (temp +1 <=tempDeseada){
   digitalWrite(releCaldera, LOW);
 }

Hola buenas, ¿así consigo una histéresis de 1ºC?
Citar
#11
Umm... a la tarde cuando tenga un momento lo veo... lo he hecho antes para un sistema dw terrarios y deberia echarle un ojo...
Te ha funcionado el codigo? Recibes un "tempmax=loquesea" en el arduino?

Me interesa saberlo, pues no se que es lo que envias mediante thingspeak... si puedes mandar textos directamente y los recibes tal cual en el arduino puedes hacer de todo...
Citar
#12
Buenas, a ver, que me explico fatal....

De thingspeak lo único que hago es enviar datos desde el sensor de temperatura hasta la web, luego con una aplicación de thingspeak en el móvil puedo consultar la temperatura (sí se puede profundizar más, pero de momento para consultar la tª me sobra).

Lo que quería, y es lo que ya tengo, gracias a tus aportes es poder enviar desde mi teléfono móvil a la caldera la señal de encendido, y a su vez poder enviar también la temperatura deseada, esto último es lo que se ha hecho. Lo que hago es que mediante appinventor creo una aplicación y le envío a través de la web un texto del estilo; "http://192.168.1//temDeseada23", el código del ESP8266 coge los 23 y los pasa a la variable temDeseada, y así puedo controlar la entrada/salida gpio para encender o apagar la caldera y con la appinventor enviar la temperatura deseada.

Todo eso lo tenía a través de mi wifi de casa, pero gracias a que he estado mirando el tema de las DNS dinámicas he conseguido poder gestionar todo desde los datos del móvil o desde culquier otra parte del mundo.

Ahora lo que quiero es ajustar la histéresis, que creo que con el código que te he enviado en el post anterior lo consigo, y ya tener un termostato 100% funcional controlado desde cualquier parte del mundo y con un coste de 10 euros.

Que por cierto viendo ahora mismo el código de la histéresis que te he apuntado antes, creo que he hecho una burrada sin sentido.....
Citar
#13
El codigo que actualmente utilizo para la gestion de 12 terrarios es este:
Código:
if (tempTerr_1 + histeresis >= tempObjetivoActual && tempTerr_1 > 0)  digitalWrite(HEATER_1, HIGH); 
   else if (tempTerr_1 < tempObjetivoActual && tempTerr_1 > 0) digitalWrite(HEATER_1, LOW);
   else digitalWrite(HEATER_1, HIGH); //Si no se da ningún caso, rele off por seguridad
 


Con esto lo que logro es que caliente hasta la temperatura deseada y luego se apague y no encienda hasta que la temperatura baje por debajo de la temperatura objetivo  menos la histereris.
Se que puede resultar confuso el código al principio... pero el código hace uso de los "elseif" y su particularidad de "Si se ejecuta el primer if, ignoro todos los siguientes"... es más, hasta yo que soy el que ha hecho esté código me he quedado un buen rato intentando comprender por que carajo lo hice asi y dudando de si eso funcionaba... y eso que lleva funcionando meses y no ha fallado aun.

El código necesario para ti será este:

Declara como global una variable con la histeresis:
Código:
float histeresis = 0.5;

Y luego, abajo, donde gestionas la temperatura:
Código:
if (calderaHabilitada){
  if (temp + histeresis >= tempDeseada && temp > 0)  digitalWrite(releCaldera, HIGH); 
     else if (tempTerr_1 < tempDeseada && temp > 0) digitalWrite(releCaldera, LOW);
     else digitalWrite(HEATER_1, HIGH); //Si no se da ningún caso, rele off por seguridad
} else {
  digitalWrite(HEATER_1, HIGH); //Caldera deshabilitada, rele off
}
 

Si en tu zona llegases a bajar de 1ºC podrías tener problemas... dudo que sea el caso, en ese caso deberías eliminar los "&& temp > 0", en mi caso los puse por seguridad, ya que un sensor de temperatura de este tipo averiado da una lectura de 0ºC, y en ese caso, la manta de las ranas quedaría encendida siempre y se cocerían un poco en verano.
Citar
#14
Código:
if (calderaHabilitada){
 if (temp + histeresis >= tempDeseada && temp > 0)  digitalWrite(releCaldera, HIGH);
    else if (temp < tempDeseada && temp > 0) digitalWrite(releCaldera, LOW);
    else digitalWrite(releCaldera, HIGH); //Si no se da ningún caso, rele off por seguridad
} else {
 digitalWrite(releCaldera, HIGH); //Caldera deshabilitada, rele off
}

Entiendo que esa parte del código queda así, ¿no?, porque había mezcla del código de los terraqueos con lo que me has pasado para mi proyecto....

De todas formas en la segunda línea, ¿no debería ser releCaldera, LOW?
Citar
#15
Ups, si, se me ha colado esa variable.
HIGH para mis relés es tener el relé desconectado, LOW es tenerlo habilitado, la lógica esta invertida... así vienen las placas de arduino con relés que me ha tocado utilizar.
Si tus relés se activan en HIGH debes invertir la lógica en ese código.
Citar
#16
Código:
if (calderaHabilitada){
 if (temp + histeresis >= tempDeseada && temp > 0)  digitalWrite(releCaldera, LOW);
    else if (temp + histeresis <= tempDeseada && temp > 0) digitalWrite(releCaldera, HIGH);
    else digitalWrite(releCaldera, LOW); //Si no se da ningún caso, rele off por seguridad
} else {
 digitalWrite(releCaldera, LOW); //Caldera deshabilitada, rele off
}

OK, entiendo que quedaría así, en la tercera línea he incluido la varibla histéresis, y "<=" también puesto que no estaba en lo que me has enviado tú, supongo que estará bien, pero con el código soy muy malo.....así que el código que pego creo que sería el definitivo, ¿no?
Citar
#17
No, el código que te  he pasado es el correcto, solo debes invertirle la lógica, cambiar HIGH por LOW y LOW por HIGH, si le metes lo de la histeresis en el "elseif" o le metes el <= en lugar de el < no funcionará correctamente.
Código:
if (calderaHabilitada){
 if (temp + histeresis >= tempDeseada && temp > 0)  digitalWrite(releCaldera, LOW); 
   else if (temp < tempDeseada && temp > 0) digitalWrite(releCaldera, HIGH);
   else digitalWrite(releCaldera, LOW); //Si no se da ningún caso, rele off por seguridad
} else {
digitalWrite(releCaldera, LOW); //Caldera deshabilitada, rele off
}

El cambio de < a <= puede que no te cause problemas, pero lo de añadir el histeresis si, prueba con el código que te acabo de pasar.

Este código lo que deberia hacer es esto:
Si tu temperatura deseada es 22ºC y la histeresis es de 0.5ºC
- En caso de que la temperatura este entre 21.5 y 22ºC, caldera apagada
- En caso de que la temperatura sea menor de 21.5ºC, caldera encendida (Si la tienes habilitada desde el movil)

Con esto absorbes algo el error de los sensores y aparte evitas que te este el rele conmutando de seguido y te casque prematuramente, ni que decir tiene que a la caldera le sentaria como el culo estar encendiendo y apagando cada 5 segundos... te recomiendo ponerle de histeresis 1 o 2º para evitarlo... habitualmente cuando un sistema aporta calor, aunque se apague, este sigue aportando calor durante un rato, asi que que no te extrañe que se apague la caldera y veas que la temperatura sigue subiendo un buen rato.
Citar
#18
Oye muchísimas gracias por todo, voy a probar y te voy contando...
Citar