Control de calefacción central con radiadores. (Heating control NODEMCU)

Saludos y gracias por vuestro tiempo. Estoy estancado con un problema y no sé como solucionarlo, estoy con un proyecto de control de zonas para la calefacción central. En el código de abajo quiero que 2 sensores DHT22 me hagan lecturas, y al seleccionar una temperatura, que se me activen los relés de los radiadores y el de la caldera, ejemplo:

  • Despacho, lo quiero a 23 grados, al estar a 21 se activa el relé del radiador y el relé de la caldera.
  • Salón, lo quiero a 22 grados, al estar a 22.5 el relé del radiador no se activa y el relé de la caldera se desactiva.

¿Cómo hago para que el relé de la caldera, mientres haya un radiador en marcha no se desactive?

void loop() {

  if (millis() > anteriorRefreshDatos + 2000){
    anteriorRefreshDatos = millis();
    float tempDespacho = dhtDespacho.readTemperature();
    float tempSalon = dhtSalon.readTemperature();
      if (isnan(tempDespacho) || isnan(tempSalon)){ 
      Serial.println("Fallo en lectura de temperatura");
      return;}
        if (calderaHabilitada = 1){
          if (tempDespacho + histeresis >= tempDeseadaDespacho && tempDespacho > 0 ) {
            digitalWrite(releDespacho, LOW);
            digitalWrite(releSalon, LOW);
            digitalWrite(releCaldera, LOW);
            }
            if (tempSalon + histeresis >= tempDeseadaSalon && tempSalon > 0 ) {
            digitalWrite(releDespacho, LOW);
            digitalWrite(releSalon, LOW);
            digitalWrite(releCaldera, LOW);
            }
        else if (tempDespacho < tempDeseadaDespacho && tempDespacho > 0 )
        { 
        digitalWrite(releDespacho, HIGH);
        digitalWrite(releSalon, HIGH);
        digitalWrite(releCaldera, HIGH);}
        else if (tempSalon < tempDeseadaSalon && tempSalon > 0 )
        { 
        digitalWrite(releDespacho, HIGH);
        digitalWrite(releSalon, HIGH);
        digitalWrite(releCaldera, HIGH);}
      else
      {
        digitalWrite(releDespacho, LOW);
        digitalWrite(releSalon, LOW); 
        digitalWrite(releCaldera, LOW); 
      }

      }

Sin ver el codigo, pues no está, dificil va a ser que alguien te diga donde esta el error o como modificar para que haga lo que quieres.

Pero bueno supongo que lo que te pasa es que cuando una de las habitaciones le dice al rele "apagate" y otra de las habitaciones aun necesita que esté funcionando, la caldera hace caso a la orden de apagarse.

es esto?

Para hacer que la caldera siga encendida si hay algún relé activo podes usar una función OR.
Por ejemplo: if (rele1==HIGH || rele2==HIGH || rele3==HIGH) { caldera=HIGH }

si lo que intentas que es que mientras haya un sensor que demande que la caldera esté activa aunque otro/s no la demanden, lo tienes que hacer comparando sensores, no individualmente, es decir que si alguno de los sensores esta en temperatura de trabajo el estado del rele sea HIGH

cuando una de las siguientes opciones sean verdad---> haga tal (encienda o mantenga encendido)
y cuando todas las siguientes opciones sean verdad ---> haga cual (apague)

No se si me explico, pero aqui puedes ver como puedes coger la idea para hacerlo

Comparadores

Vamos por partes, primero tienes que saber que necesitas una temperatura de activar el rele y en esa misma otra que lo mantenga durante un tiempo, para que suba ciertos grados, sino estara siempre activandose y desactivandose todo el rato, al no lograr un margen.

Veamos si es algo asi lo que buscas...

Debes de tener dos lecturas separadas, ejemplo t1 sensor 1 y t2 sensor 2 (vamos a pensarlo para un solo rele de caldera)

if ( ((t1) <= 20.00) || ((t2) <= 22.00)) si la temperatura t1 es menor o igual a 20º O t2 menor de 22º, si una de las dos es verdad (o ambas lo son) hace lo siguiente

{
active el rele
}

Para que lo apague solamente cuando ningun sensor demanda que esté activado
if( ((t1) > 23.00) && ((t2) > 25.00)) si la temperatura t1 es mayor a 23º Y t2 mayor de 25º , si las dos son verdad hace lo siguiente

{
apaga el rele
}

Si lo pones asi en este orden creo que no debes poner nada mas, te es suficiente, recuerda que el loop corre siempre desde arriba a abajo buscando que hacer, por tanto aunque empiece a bajar la temperatura pongamos en t2 de 25º a 24º no se va a activar porque antes le estas diciendo que si en t2 no es menor o igual a 22º no se active. Si le cambias el orden en el loop entonces ya si hay que hacer unos cambios.

Con respecto a lo de ponerle unos grados más para que se desactive ya te digo que es para que le de tiempo a calentar y mantener una temperatura, sino tal como se pare empezara a perder temperatura y estará saltando todo el rato, al ser la diferencia de solamente 0,1º si le pones decimales, o de 1º si no se la pones.

Muchas gracias por tu tiempo :wink:

""Vamos por partes, primero tienes que saber que necesitas una temperatura de activar el rele y en esa misma otra que lo mantenga durante un tiempo, para que suba ciertos grados, sino estara siempre activandose y desactivandose todo el rato, al no lograr un margen.""

--Sí, para ello tengo programada la histéresis, de esas forma los relés no están siempre en ON/OFF.

HISTÉRESIS

if (tempDespacho + histeresis >= tempDeseadaDespacho && tempDespacho > 0 )

El problema no es hacer lecturas de los relés, eso lo tengo conseguido, el problema es conseguir que el relé de la caldera se encienda solamente cuando hay un radiador pidiendo calor, y que cuando no haya ningún radiador pidiendo calor, el relé de la caldera se desconecte.

Las temperaturas que he puesto antes son informativas, los rangos en cada uno de los sensores van entre los 21 y los 26 grados y los gestiono con "tempDeseadaDespacho", "tempDeseadaSalon", "tempDeseadaMatrimonio", "tempDeseadaInvitados".

Realmente son 4 zonas las que voy a usar, pero en la ayuda he puesto solamente 2 para que fuera más fácil el ejemplo.

He probado con algo así, sólo con la zona del despacho, pero si hago eso mismo con las 4 zonas al final no me funciona correctamente:

if (calderaHabilitada = 1){
          if (tempDespacho + histeresis >= tempDeseadaDespacho && tempDespacho > 0) { 
          digitalWrite(releCaldera, LOW);
          digitalWrite(releDespacho, LOW);
        } else  {
          (tempDespacho < tempDeseadaDespacho && tempDespacho > 0);
        }
        digitalWrite(releDespacho, HIGH);
        digitalWrite(releCaldera, HIGH);
          } else { digitalWrite(releDespacho, LOW);
      }

Lo que pretendo es lo siguiente, ejemplo:

  • Quiero despacho a, por ejemplo 23 grados, al estar a 21 se activa el relé del radiador y el de la caldera.
  • Quiero el Salon a, por ejemplo 24 grados, al estar a 20 se activa el relé del radiador y el de la caldera.
  • Quiero Matrimonio, por ejemplo a 21 grados, al estar a 22 grados no se activa el relé, y manda orden de desconectar el relé de la caldera.
  • Quiero Invitados a 22 grados, como está a 23 grados no hace nada.

El problema me viene para poder mover cada uno de los relés de los radiadores y que a su vez me active la caldera, siempre que haya un relé de un radiador activo. Cuando todos los radiadores estén desactivados, que el relé de la caldera se desconecte.

Te dejo un ejemplo que he estado usando para gestionar un sólo relé, cuando tenía la instalación mas sencilla en casa, solamente usando un sensor de temperatura y un relé:

if (millis() > anteriorRefreshDatos + 20000){
    anteriorRefreshDatos = millis();
    float temp = dht.readTemperature();
    float humi = dht.readHumidity();
      if (isnan(temp) || isnan(humi)){ 
      Serial.println("Fallo en lectura de temperatura y humedad");
      return;}
        if (calderaHabilitada = 1){
          if (temp + histeresis >= tempDeseada && temp > 0)  digitalWrite(releCaldera, LOW);
        else if (temp < tempDeseada && temp > 0) digitalWrite(releCaldera, HIGH);
      else digitalWrite(releCaldera, LOW); 
      }

Lo que pretendo es conseguir lo de arriba, pero con 4 DHT22 y 5 relés, uno por cada zona y el de la caldera. La parte lógica se me escapa.

Gracias por tu tiempo.

¡Cuidado! La línea de código:

if (calderaHabilitada = 1){

No está haciendo lo que se espera que haga. La condición se cumple siempre porque lo que está haciendo es asignar el valor 1 a la variable calderaHabilitada y verificar que el valor asignado es distinto de cero, dando siempre por cierta la condición del if. Dicho de otro modo, esa línea hace que calderaHabilitada pase a valer 1 y que siempre se cumpla la condición. Es el fallo que todos cometemos de vez en cuando, el de poner un igual (=) en lugar de un doble igual (==) en las comparaciones.

La línea debería de ser:

if (calderaHabilitada == 1){

Hay que añadir un igual y poner == en lugar de = para que funcione como esperamos.

No he mirado sino por encima en código que has puesto, así que no sé si ese condicional es lo único que impide que tu programa haga lo que quieres. Mi consejo es que revises todos los "if" y, una vez corrergirlos, prueba a ver si sólo es eso lo que te está fallando.

pero y si todo funciona y lo que buscas ahora es hacer que el rele de la caldera solamente funcione cuando lo demande un rele de uno o varios radiadores, porque no lo dices sencillamente que cuando alguno de los reles estén en High, lo haga tambien el de la caldera, y cuando esten todos en Low, pase a estarlo tambien el de la caldera?

leyendo ese pin de salida (pin hacia el rele de cualquier radiador) sabras su estado y con ello el que deba pasar a estar el de la caldera.

Sin todo el codigo, conexiones electricas y material que usas... sólo te van a poder decir puntualizaciones concretas, que igual realmente no sea lo que te ocurra, pues si como dices con 1 te funciona igual es que al poner más hay algun conflicto en la suma de todo y no en partes concretas

@Mikms

Muchas gracias por tu aporte, sí, finalmente he comprobado que el error está en que hay un conflicto en la suma de todo. Realmente me estoy volviendo loco con los IF y demás, en serio. Estoy probando mil combinaciones y seguramente sea mucho más simple de lo que tengo en la cabeza, pero mis limitaciones en programación no me dejan solucionar el problema.

Adjunto muestra básica del circuito. Son 4 sensores DHT y 5 relés. 4 relés para el control de las electrovávulas de los radiadores y un quinto relé para el control de la caldera.

Tengo casi terminado el código (me vais a disculpar por la forma de escribir el código y por las barbaridades que podéis encontrar, no soy informático y funciono a base de copiar código de por ahí y prueba y error). Ahora mismo y con el código que tengo escrito consigo configurar el NODEMCU desde mi teléfono móvil, enviar peticiones GET desde el móvil con un programa android y ver todos los datos en thingspeak.

Pero sigo con el problema del relé de la caldera. Si hago una petición GET pidiendo calor al radiador del DESPACHO, consigo que el relé del despacho se active, si hago un GET para que se apague, lo hace. Igual con los reles del Salon y de matrimonio. Pero no se activa el relé de la caldera.

Peeeeeerooooo si hago un GET al radiador de invitados, éste se activa y me activa el relé de la caldera, aquí sí, y si le hago un GET para que se apague invitados, el relé de invitados se desactiva y también el relé de la caldera.

Así que sí, es un problema en los IF, pero no sé cómo solucionarlo.

Os adjunto la parte del código en el que fallo. (Si queréis ver todo el código os lo mando o cuelgo en el post, no me deja subirlo porque excede de 9000 palabras. Aprovecho y como sugiere el admin, adjunto el archivo .INO con el programa completo que estoy desarrollando. Desde aqui dar las gracias y pedir disculpas por usar de forma incorrecta el foro, lo siento.

//--------------------RELE DESPACHO----------------------------------------------------------------------------------------
            if (tempDespacho + histeresis >= tempDeseadaDespacho && tempDespacho > 0){
            digitalWrite(releDespacho, LOW);
            digitalWrite(releCaldera, LOW); 
            }
              if (tempDespacho < tempDeseadaDespacho && tempDespacho > 0){ 
                digitalWrite(releDespacho, HIGH);
                digitalWrite(releCaldera, HIGH);
        } 
       

     //----------------------RELE SALON----------------------------------------------------------------------------------------

           if (tempSalon + histeresis >= tempDeseadaSalon && tempSalon > 0){
            digitalWrite(releSalon, LOW);
            digitalWrite(releCaldera, LOW); 
            }
              if (tempSalon < tempDeseadaSalon && tempSalon > 0){ 
                digitalWrite(releSalon, HIGH);
                digitalWrite(releCaldera, HIGH);
        } 
    

     //-----------------------RELE MATRIMONIO---------------------------------------------------------------------------------------


           if (tempMatrimonio + histeresis >= tempDeseadaMatrimonio && tempMatrimonio > 0){
            digitalWrite(releMatrimonio, LOW);
            digitalWrite(releCaldera, LOW); 
            }
              if (tempMatrimonio < tempDeseadaMatrimonio && tempMatrimonio > 0){ 
                digitalWrite(releMatrimonio, HIGH);
                digitalWrite(releCaldera, HIGH);
        } 
      

     //------------------------RELE INVITADOS--------------------------------------------------------------------------------------

           if (tempInvitados + histeresis >= tempDeseadaInvitados && tempInvitados > 0){
            digitalWrite(releInvitados, LOW);
            digitalWrite(releCaldera, LOW); 
            }
              if (tempInvitados < tempDeseadaInvitados && tempInvitados > 0){ 
                digitalWrite(releInvitados, HIGH);
                digitalWrite(releCaldera, HIGH);
              }

          //---------------------RELE CALDERA----------------------------------------------------------------------------------------------
     if (releDespacho == LOW || releSalon == LOW || releMatrimonio == LOW || releInvitados == LOW){ 
            digitalWrite(releCaldera, LOW); 
            }

PRUEBAS.ino (15.8 KB)

Si el código supera 9k entonces lo adjuntas como .zip para poder ser analizado.

@IgnoranteAbsoluto

Muchísimas gracias por tu ayuda, revisando el código he podido comprobar que realmente VAL no me sirve para nada, no sé en su día por qué lo utilicé, pero gracias a tu aporte lo he quitado y aligerado el código. Mil gracias.

Así mirando por encima.....Con esto le estas diciendo que si alguna de las siguientes opciones es verdad te apague el rele de la caldera

|| (Verdadero si alguna de las condiciones es verdadera). Es imposible entonces que si tienes tan solo uno de esos radiadores apagado te pueda encender el rele de la caldera

if (releDespacho == LOW || releSalon == LOW || releMatrimonio == LOW || releInvitados == LOW){
            digitalWrite(releCaldera, LOW); 
            }

Entiendo que tendrias que usar
&& (Verdadero sólo si todas condiciones son verdaderas) para que en caso de que TODOS los radiadores esten apagados, mantenga apagado el rele de la caldera

if ((releDespacho == LOW) && (releSalon == LOW) && (releMatrimonio == LOW) && (releInvitados == LOW))
           {
            digitalWrite(releCaldera, LOW); 
            }

(Debes meter entre parentesis cada cosa que pretendas comparar)

if (tempDespacho + histeresis >= tempDeseadaDespacho && tempDespacho > 0){
            digitalWrite(releDespacho, LOW);
            digitalWrite(releCaldera, LOW); 
            }
              if (tempDespacho < tempDeseadaDespacho && tempDespacho > 0){ 
                digitalWrite(releDespacho, HIGH);
                digitalWrite(releCaldera, HIGH);}
        else{
          digitalWrite(releDespacho, LOW); 
          digitalWrite(releCaldera, LOW); 
        }

y recuerda que cada cosa que quieres comprarar debes tenerla metida entre parentesis para que sepa que parte concreta es la que estas comparando con cual

if ( (tempDespacho < tempDeseadaDespacho) && (tempDespacho > 0) )

Porque le dices siempre .... xxxxxxxl && xxxxxx MAYOR de 0?, para que que repites siempre que sea mayor de 0, en caso de ser menor no debe activarse? es que lo pones tanto en activarse como en desactivarse, por lo que no entiendo bien para que sirve (lo he mirado por encima, y lo mismo me he perdido algo)

esta parte? ... ya le estas diciendo arriba que si la temperatura es tal lo apague, y si es otra tal temperatura que lo encienda, entonces se entiende que si es la temperatura de arriba lo mantendrá apagado, y si es la de abajo lo mantendrá encendido, por lo que el "SINO apagalo", creo que no tiene mucho sentido.

else{
          digitalWrite(releDespacho, LOW); 
          digitalWrite(releCaldera, LOW); 
        }

Un detalle (que a mi ya me volvio loco una vez y ademas con temas de temperatura y era ese despiste el que me daba fallo). El programa siempre lee de arriba a abajo, creo que lo mejor es siempre ponerle que primero sea encender y debajo apagar, para cuando compruebe no haya que ponerle más ordenes de apagar debajo cuando ya la tienes justo arriba, que igual es lo que te pasa y por eso usas ese ELSE,

@Mikms

Muchas gracias por todo. Resulta que los 2 NODEMCU que tengo se han estropeado, he pedido un par mas por Amazon y lo que tarden en llegarme. En cuanto los tenga en casa me pongo con todo lo que me has comentado y te voy informando, esto tengo que hacerlo funcionar como sea, jeje..

Muchas gracias, te cuento en breve.

Como que se han estropeado? que has hecho para que eso ocurra, describe como los estas usando porque seguramente repetirás la falla con los nuevos y debes comenzar a usarlos debidamente.
No se queman porque si.

Tienes un esquema de como esta todo conectado?

No se han quemado, de hecho por eso he reinstalado el IDE de arduino. Creo que se han corrompido, porque comenzaron a sacar mensajes y simbolos raros y no podía hacer nada con ellos. He probado a reinstalar el firmware con el programa nodemcu-flasher-master y luego a intentar gestionarlos con el programa ESPlorer.

@surbyte

Pues como en el diagrama que hay un poco más arriba, de hecho sólo lo estoy alimentando con el usb, he estado bastantes días haciendo problemas sin problemas. Sí es verdad que cada vez que cargaba el sketch, muchas veces no me leía las lecturas de los sensores de temperatura y me tocaba desconectar la alimentación (3.3v) y volver a conectarla. Pero solo quitaba la alimentación de los DHT.

De hecho no me reconocen ni los comandos AT.

Si me carga el firmware, pero una vez cargado está corrompido.

Saludos, antes de nada dar las gracias a tod@s por la ayuda recibida. Se aprende mucho, peleando uno mismo y con la ayuda del resto. Dar las gracias a @surbyte, @Mikms, @Pablo_Lucini, @IgnoranteAbsoluto por vuestros aportes, de los cuales he ido agarrando (que no cogiendo, que aquí hay mucho Argentino) y gracias a ello he conseguido poner todo en marcha, salvando una serie de errores que me había surgido tras instalar el nuevo IDE de arduino y actualizar sus librerías.

Os dejo abajo las versiones, tanto del IDE de arduino como de las librerías y sus versiones. OJO, esto me está funcionando a mí, pero quizás a vosotr@s os funciona con otras versiones, esto es un misterio. Yo lo he sufrido, una gran cantidad de conflictos entre distintas librerías. Hacer mención especial a que es muy importante el orden en el que se definen las librerías al inicio del código, yo como tengo el orden, es el que me vale. (No me preguntéis el por qué, porque no tengo ni idea. Aquí gracias @surbyte).

El programa en cuestión lo que hace es gestionar 5 relés que hay en 5 radiadores, cuando un radiador demanda calo, éste se activa y a su vez activa el relé de la caldera. Cuando ningún relé demanda calor, la caldera se apaga. Así que lo que tengo es un control de calefacción por zonas, para ello tengo cableada toda la instalación, ya que en una reforma pude aprovechar y hacerlo.
Todo ello lo gestiono desde internet (móvil, pc, tablet, portátil, etc). Los datos de temperatura los subo a thingspeak y mediante Json hago las consultas y demás.
El NODEMCU se puede configurar desde el teléfono móvil, gracias a la librería WIFIMANAGER.H, de esta forma se pueden cambiar datos tales como el IDE, PASS del wifi de casa y el IP del NODEMCU.
Realmente es un programa muy básico, pero para uno como yo que no sabe informática y que se dedica a robar código, pues es un logro, al menos así lo veo.
Decir que he hecho ingentes búsquedas de información por la web, y que una de las claves principales me las dio el vídeo de un Tailandés (como suena).

Así que a buscar, leer y pelear. El que algo quiere, algo le cuesta.

Os adjunto el código .INO del proyecto para que el que lo desee, lo pille y haga lo que quiera con él. Para cualquier consulta, aquí me tenéis.

IDE de arduino versión 1.8.9

Tarjetas ESP8266

Core NODEMCU: Librería https://github.com/esp8266/Arduino Version del core, 2.4.0

Librerías usadas y versiones instaladas

ESP8266Wifi.h: Librería https://github.com/esp8266/Arduino
Thingspeak.h : Librería https://github.com/mathworks/thingspeak-arduino Versión, 1.4.3
WifiManager.h: Librería https://github.com/tzapu/WiFiManager, versión, 0.14.0
ArduinoJson.h: Librería https://github.com/bblanchon/ArduinoJson, versión 5.13.5 (ojo, la actual está por encima de la Versión 6, hay que hacer downgrade para mi código)
ESP8266mDNS.h está dentro del paquete de arduino.
DNSserver.h está dentro del paquete de arduino.
ESP8266WevServer.h: Librería https://github.com/esp8266/ESPWebServer
WifiCliente.h está dentro del paquete de arduino.
WifiServer.h está dentro del paquete de arduino.
DoubleResetDetector.h: Librería https://github.com/datacute/DoubleResetDetector, Versión 0.0.2
LiquidCrystal_I2c.h: Librería https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library, Versión 1.0.6
Wire.h está dentro del paquete de arduino.

DEFINITIVO_OPERATIVO_100x100.ino (17.1 KB)

En el post#15, le cambias el firmware al nodemcu. Para que haz hecho eso?

@surbyte

Hola, sí, ante mi desesperación ya que los dos NODEMCU me dejaron de funcionar, probé hasta cargar el firmware de nuevo, por si se habían corrompido. Finalmente puedo confirmar que hay un NODEMCU que está muerto, el otro al final me está funcionando. Si crees conveniente que elimine ese POST, no problem.

Pues enhorabuena, ya que ademas de hacerlo funcionar has reducido el sketch un montón, un saludo