Go Down

Topic: Control de encendido y apagado con RTC y Relay. [Solucionado] (Read 3186 times) previous topic - next topic

steel_series

Tengo hecho un timer con un RTC (DS3231) y un Relay, es para que una lampara se encienda y apague en el horario que yo le indico mediante un LCD y un par de botones, los parametros se almacenan en la EEPROM cada vez que se setea una hora.

Si yo le indico, por ejemplo, que la lampara se encienda a las 21:15 Hs. y se apague a las 06:15 Hs. simplemente almaceno las 4 variables y las comparo con la hora actual del RTC.

Code: [Select]

hora_set_on = EEPROM.read(1);
minutos_set_on= EEPROM.read(2);

hora_set_off= EEPROM.read(3);
minutos_set_off= EEPROM.read(4);


if  ( (horas_rtc == hora_set_on ) && (minutos_rtc == minutos_set_on ) )
                
     {                
       digitalWrite(relay, LOW);
     }

if  ( (horas_rtc == hora_set_off ) && (minutos_rtc == minutos_set_off ) )
    
     {
        digitalWrite(relay, HIGH);            
      }


Mi problema es el siguiente:

Si hay un corte de luz o una caída de tensión y el Arduino se apaga o reinicia, cuando vuelve a funcionar, la lampara queda apagada, aun estando dentro del horario programado para que esté encendida.

Me gustaría que la lampara siga encendida cuando el suministro eléctrico regrese de un corte, siempre y cuando este dentro de la hora que yo programé.

un ejemplo sería:

Code: [Select]

if  ( (horas_rtc >= hora_set_on ) &&  (horas_rtc <= hora_set_off ))
  
     {                
       digitalWrite(relay, LOW);
     }
else
     {                
       digitalWrite(relay, HIGH);
     }

 


Pero obviamente eso esta mal, aunque en algunos rangos horarios si funcione, cuando entran en juego los minutos, el código no me sirve, porque los minutos van siendo mayores y menores cada una hora.

Incluso si quiero hacer lo mismo solo con las horas, pero que se encienda a las 23:00 y se apague a las 02:00, ya no serviría, porque cuando la hora actual llegue a las 00:00 la condición ya no se cumpliría.

Si alguno me puede ayudar a pensar un poco en como resolver lo planteado lo agradecería mucho.
La verdad es que soy nuevo en esto, seguramente hay alguna forma de resolverlo, pero mi cabeza no da para mas.

Mi alternativa hasta el momento es hacerlo por hardware, añadiendo una batería de respaldo conectada a un modulo controlador de carga en paralelo con la alimentación y un diodo, pero si se pudiese hacer por software seria lo ideal.

Me disculpo de antemano si cometí algún error en la redacción del thread.


Saludos y desde ya muchas gracias.-


ratpenat

Hola.

Yo usaría una variable en la EEPROM que pondría a 1 cuando acciono el relé y a 0 cuando lo suelto, de forma que al arrancar el arduino bastaría con leer la EEPROM y accionar el relé si la variable está a 1, por ejemplo.

Suerte

Saludos

steel_series

Hola.

Yo usaría una variable en la EEPROM que pondría a 1 cuando acciono el relé y a 0 cuando lo suelto, de forma que al arrancar el arduino bastaría con leer la EEPROM y accionar el relé si la variable está a 1, por ejemplo.

Suerte

Saludos
Es buena la idea, aunque no llega a ser del todo ideal, supongamos que el relay se enciende, se guarda la variable 1 en la EEPROM, se corta la energía y vuelve después de la hora programada para el apagado, nunca se guardaría el valor 0 y la lampara seguiría encendida hasta el día siguiente.
De todas formas lo voy a tener en cuenta a ver si se me ocurre algo mas.

Muchas gracias por el aporte!

Saludos!

surbyte

Quote
Es buena la idea, aunque no llega a ser del todo ideal, supongamos que el relay se enciende, se guarda la variable 1 en la EEPROM, se corta la energía y vuelve después de la hora programada para el apagado, nunca se guardaría el valor 0 y la lampara seguiría encendida hasta el día siguiente.
La idea esta bien pero te falto visualizar que debes detectar el corte de luz para poder informar de ello a tu alerta EEPROM.

Debo buscarlo porque me gusta darle crédito a quien lo ha dicho, pero alguien sugirió usar un Capacitor de 1F como Backup Podrias probar con algo menos tal vez... prueba.

Entonces imagina la situación. Detectas con algo de hardware que se cayó la energía pero tienes X tiempo (suficiente) para grabar en la EEPROM que tu accion no se ha completado. Al restaurase la energía lo primero que debes hacer si estas o no dentro del rango.

steel_series

La idea esta bien pero te falto visualizar que debes detectar el corte de luz para poder informar de ello a tu alerta EEPROM.

Debo buscarlo porque me gusta darle crédito a quien lo ha dicho, pero alguien sugirió usar un Capacitor de 1F como Backup Podrias probar con algo menos tal vez... prueba.

Entonces imagina la situación. Detectas con algo de hardware que se cayó la energía pero tienes X tiempo (suficiente) para grabar en la EEPROM que tu accion no se ha completado. Al restaurase la energía lo primero que debes hacer si estas o no dentro del rango.

Gracias a los dos por las ideas! Voy a ver si hago eso, con un capacitor y un divisor resistivo a un puerto analógico para detectar la caída del voltaje, o algo por el estilo.

Dejare por acá el resultado, puede que a alguien le sirva.

Saludos y gracias nuevamente!!

 

surbyte

Exactamente. Prueba que tal funciona con un capacitor electrolitico de 4700uF 16V y si te da tiempo (100mseg o mas para grabar. Necesitas mucho menos, si mal recuerdo 5mseg).

IgnoranteAbsoluto

Para comparar fácilmente horas y minutos entre sí, lo más sencillo es pasar todo a minutos multiplicando por 60 las horas y sumando los minutos. Aún así, hay que tener en cuenta un par de detalles. Uno es que normalmente la hora y minuto de inicio sí se quiere que sea "inclusiva" mientras que la hora y minuto de final no lo es, o dicho matemáticamente, el intervalo comprendido entre inicio y el fin es semiabierto por la derecha [inicio, fin)

Ejemplo práctico, queremos que se encienda a las 10:15 y se apague a las 11:30. Entonces ha de estar encendido cuando la hora (y minuto) sea mayor o igual que 10:13 y menor que 11:30 (no si es igual a 11:30)

Esto conlleva que si decimos que ha de estar encendido de 9:00 a 9:00, nunca se encenderá porque no hay ninguna hora que sea mayor o igual que 9:00 y a su vez sea menor que 9:00

Si queremos que se encienda hoy y se apague mañana, deberíamos de tener en cuenta que la hora de inicio es mayor que la de fin (ejemplo: encenderse a las 20:00 y apagarse a las 8:00). En tal caso, en el momento de la comparación, nos valdría sumar 24 horas a la hora de finalización. En tal caso debemos controlar si la hora a comparar es menor que la hora de inicio, y si se da tal condición a efectos prácticos también hemos de suponer que se trata del "día siguiente" con lo que también habría que sumarle 24 horas en el momento de comparar. En el ejemplo de encenderse entre las 20:00 y las 8:00, en el momento de hacer las comparaciones deberíamos de sumar 24 horas a la hora de final (8:00) con lo que nos daría las 32:00 horas (relativa al "día actual"), con lo que se debería de encender si la hora actual está entre las 8:00 y las 32:00. ¿Pero cómo es eso posible? Pues porque si la hora actual es igual o mayor que la hora de inicio se compara tal cual. Pero si la hora actual es menor que las 20:00 (hora de inicio) entonces le sumamos 24 horas y comparamos. Supongamos que la hora actual son las 9:00, le sumamos 24 horas y nos da las 33:00, que como es mayor que las 32:00 (la que habíamos calculado para el final) no está dentro del rango (de 20:00 a 8:00) por lo que no se ha de encender. Si en lugar de ser las 9:00 fueran las 5:00 entonces la suma de 24 horas nos da las 29:00 y esto sí que está entre las 20:00 y las 32:00, así que sí que se ha de encender.

Ahora que tenemos claro cual es la lógica (y las matemáticas) que aplicamos cuando queremos saber si una hora está entre un intervalo de horas dado, podemos hacer una función que nos lo diga:
Code: [Select]

// Función que nos indica si hora, minuto está entre la horaDesde, minutoDesde y la horaHasta, minutoHasta.
// hora y horaDesde han de tener un valor entre 0 y 23
// horaHasta puede tener un valor entre 0 y 24
// minuto, minutoDesde y minutoHasta han de tener un valor entre 0 y 59
bool estaEnMedio(byte hora, byte minuto, byte horaDesde, byte minutoDesde, byte horaHasta, byte minutoHasta) {
    int compara = hora * 60 + minuto;           // Pasamos a minutos el momento a comparar
    int desde = horaDesde * 60 + minutoDesde;   // Pasamos a minutos el inicio del intervalo
    int hasta = horaHasta * 60 + minutoHasta;   // Pasamos a minutos el final del intervalo
    if (hasta < desde) {                        // ¿El final de intervalo es antes que el inicio?
        hasta += 24 * 60;                       // Si es así, es que el final es el día siguiente, así que le sumamos un día en minutos
        if (compara < desde) {                  // En este caso miramos entonces si el momento a comparar es menor que el inicio del intervalo
            compara += 24 * 60;                 // Si es así, hacemos que el momento a comparar sea del día siguiente, sumando un día en minutos
        }
    }
    return ( (desde <= compara) && (compara < hasta) ); // Retorna verdadero si en momento a comparar está entre el inicio y el fin (si inicio y fin son iguales, nunca será verdadero)
}


Asumiendo que el relé que quieres controlar se activa a nivel bajo (LOW) con las variables que tienes definidas sólo habría que poner:
Code: [Select]

if (estaEnMedio(horas_rtc, minutos_rtc, hora_set_on, minutos_set_on, hora_set_off, minutos_set_off)) {
    digitalWrite(relay, LOW);   // Ativamos el relé
}
else {
    digitalWrite(relay, HIGH);  // Desactivamos el relé
}


Doy por sentado que las horas son de 0:00 a 24:00 (Nota: la de final sí que puede ser las 24:00, la de inicio no deberá ser nunca las 24:00 sino 0:00)

Si queremos que nunca esté "dentro" podemos poner como inicio las 0:00 y como fin las 0:00 (nunca se enciende)

Si queremos que siempre esté "dentro" podemos poner como inicio las 0:00 y como fin las 24:00 (siempre encendido)

De esta forma puedes comprobar en cualquier momento si ha de estar encendido o apagado. Espero que esto te sirva.

steel_series

Para comparar fácilmente horas y minutos entre sí, lo más sencillo es pasar todo a minutos multiplicando por 60 las horas y sumando los minutos. Aún así, hay que tener en cuenta un par de detalles. Uno es que normalmente la hora y minuto de inicio sí se quiere que sea "inclusiva" mientras que la hora y minuto de final no lo es, o dicho matemáticamente, el intervalo comprendido entre inicio y el fin es semiabierto por la derecha [inicio, fin)
[...]
Wow, eso es lo que necesitaba, voy a darle vueltas a lo que planteas para tratar de entenderlo y poder aplicarlo a mi código.

Muchas gracias por el tiempo dedicado y a todos los que se tomaron el tiempo de aportar una idea, que linda comunidad!

Saludos!!

albertoG1

Pues ya lo tienes todo montado..., pero si algún día quieres tener el control de encendido y apagado de algo por vía wifi a través de un smartphone Android o iOs, hay una aplicación que se llama "Bynk", es gratuita, se programa a través del IDE de Arduino, y con un modulito wifi (cada vez son más económicos, cuestan aún menos que un Arduino), más un relé y una fuente de alimentación puedes controlar encendido, apagado, temporizado y etcéteras.

surbyte

Quote
"Bynk", es gratuita
en tanto y en cuanto no agregas muchos controles y entonces tienes que comprar créditos para seguir sumando.

albertoG1

en tanto y en cuanto no agregas muchos controles y entonces tienes que comprar créditos para seguir sumando.
En principio tienes gratis los primeros quinientos y pico de puntos, que alcanzan para un par de interruptores y otro tanto de programadores horarios, si te enganchas (muy probable) pues por unos 5€ compras 5000 puntos, que son un montón.
Nos estamos saliendo del tema del compañero, pero creo que pagar algo (en realidad es poco) estimula a los desarrolladores de la aplicación para que sigan ampliando utilidades.
Por otra parte intuyo que ese camino es el futuro de la programación.

surbyte

Tienes razón pero dijiste que era gratuita y no es el caso y solo eso señalaba
 
Yo uso Blynk asi que no me lo tienes que vender porque ya lo he adoptado incluso con este detalle que no me molesta en lo absoluto.

albertoG1

Yo uso Blynk asi que no me lo tienes que vender porque ya lo he adoptado incluso con este detalle que no me molesta en lo absoluto.
Jaja ;)
Lo sé, y además me prometiste antes de tus vacaciones que harías un pequeño tutorial en español porque toda la documentación está en inglés y en ruso, y en mi caso, porque no acabo de pillar el tema de los pines virtuales del Blynk.
Pero todo a su tiempo, que cada vez tienes más responsabilidades dentro del foro.

steel_series

Después de unos días de prueba, puedo decir que el código de "IgnoranteAbsoluto" anda a la perfección , si alguien necesita lo mismo, puede usarlo tranquilamente, la explicación es excelente y pude adaptarlo a mi código sin problemas.

Ya había editado el titulo como [Solucionado], no se si eso me corresponde a mi, o los moderadores deben cerrar el thread.

Saludos y gracias a todos!

Go Up