Diseño Controlador Acuario

Hola
Con la guia de Daniel_Arg se realizara un controlador de acuario, donde se iran agregando partes del código hasta completarlo, constara menú para modificar parametros luz,Hora,fecha,etc, lcd para visualizar información, sensor de temperatura y relés. La idea es tener una base y que cualquiera pueda realizar su controlador y porque no ampliarlo

Materiales:
Arduino Puede ser Nano, Uno o Mega
Reloj DS3231
Lcd 20x4 con I2C
Sensor temperatura DS18B20
Encoder rotatorio con pulsador
Resistencia 4,7k - 1/4w =1
Resistencia 1k - 1/4w =4
Led Blanco, Rojo, Azul
Fuente de poder 9v
Reles arduino 5v 2 canales
transistor 2N2222
Protoboard
Cables coneccion

Esquema fácil de leer
Nota: La entrada de alimentación varia según su arduino

Adjunte la imagen

Librería

        encoder      :  https://github.com/mathertel/RotaryEncoder

        RTC            :  https://github.com/adafruit/RTClib
        (post 36 libreria RTC)

        OneButton  :https://github.com/mathertel/OneButton

        LiquidCristal:https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads/
         (Newliquidcrystal_1.3.5)

Archivos adjunto con Sketch base

En ultima pagina se adjunta Sketch final

PruebMenu_Enco.ino (9.79 KB)

Hola voy a hacer mi aporte:
En esta parte del código:

void loop() {
 unsigned long currentMillis = millis();
 button.tick();
 LeeEncoder(0, 7, 1, 1);  // Lee el enconder de 0 a 7, de a 1 paso y con tope final.

 if (currentMillis % 6000 < 5) {  //  Si el resto de dividir currentMillis por 6000 da menos que 5...
 ImprimeFecha();
 ImprimeHora();
 ImprimeTemp();
 }
}

se va a cumplir cuando sea por ejemplo 6000,6001,6002,6003,6004 y en el "mejor de los casos" pero en el transcurso se cumple y se va a actualizar como 20 veces aquí un ejemplo de lo que digo:
Prueba1.png
Ahora asi como muestra por serial va actualizar en la pantalla para lo cual presentó algo que puede ser mejor tendrías que añadir las siguientes líneas y borra en el que tu tienes, espero se entienda

#define tiempoPresentarDatos 6000UL // Tiempo al que se quiera realizar las acciones ejemplo 6s (1000ms = 1s)
unsigned long tiempoActualDatos = 0;

void loop() {
 if (millis() - tiempoActualDatos >= tiempoPresentarDatos) { // Si el tiempo actual menos el tiempo anterior  es mayor o igual a 6 segundos 
 tiempoActualDatos = millis(); // Actualiza el tiempo Actual
 //Resto del codigo que quieras que se cumpla cada 6 segundos
 }
}

Prueba2.png
Ahora también por ejemplo en esta parte utilizas una función y en el cual en una condición la utilizas para para comprobar si tiene tope o no

void LeeEncoder(int ROTARYMIN, int ROTARYMAX, int ROTARYSTEPS, int ROTARYTOPE )
{ 
  encoder.tick();  // Lee el encoder y actualiza el puntero. La librería lleva la cuenta desde 0.
  newPos = encoder.getPosition() * ROTARYSTEPS; // Asigna a newPos el puntero del encoder multiplicado por los pasos. 

  if (ROTARYTOPE == 1) {  // Si el rotor tiene tope entonces no se pasa de valor
    if (newPos < ROTARYMIN) {    // Solo si el puntero es menor a Valor Mínimo ->
      encoder.setPosition(ROTARYMIN / ROTARYSTEPS);  // Se fija el puntero al valor mínimo por los pasos
      newPos = ROTARYMIN;  
    }
    if (newPos > ROTARYMAX) {   // Solo si el puntero es mayor a Valor Máximo ->
      encoder.setPosition(ROTARYMAX / ROTARYSTEPS);  // Se fija el puntero al valor mínimo por los pasos
      newPos = ROTARYMAX;

    }
  }

  if (ROTARYTOPE == 0) {  // Si el rotor SI tiene tope entonces se pasa del valor máximo al mínimo y viceversa.
    if (newPos < ROTARYMIN) {  // Solo si el puntero es menor a Valor Mínimo ->
      encoder.setPosition(ROTARYMAX / ROTARYSTEPS);
      newPos = ROTARYMAX;  // Entonces el puntero saltará del mínimo al máximo

    }
    if (newPos > ROTARYMAX) { // Solo si el puntero es mayor al Valor Máximo ->
      encoder.setPosition(ROTARYMIN / ROTARYSTEPS);
      newPos = ROTARYMIN;  // Entonces el puntero saltará del máximo al  mínimo.
    }
  }
}

lo que veo un poco innecesario ya que ese no va a cambiar en el transcurso del funcionamiento si no solo cuando se configura por lo que creo que se podría utilizar de esta forma como ejemplo

#define encoderTope 1
void loop() {

#if encoderTope == 1
 if (newPos < ROTARYMIN) {    // Solo si el puntero es menor a Valor Mínimo ->
 encoder.setPosition(ROTARYMIN / ROTARYSTEPS);  // Se fija el puntero al valor mínimo por los pasos
 newPos = ROTARYMIN;
 }
 if (newPos > ROTARYMAX) {   // Solo si el puntero es mayor a Valor Máximo ->
 encoder.setPosition(ROTARYMAX / ROTARYSTEPS);  // Se fija el puntero al valor mínimo por los pasos
 newPos = ROTARYMAX;
 }
#else 
 if (newPos < ROTARYMIN) {  // Solo si el puntero es menor a Valor Mínimo ->
 encoder.setPosition(ROTARYMAX / ROTARYSTEPS);
 newPos = ROTARYMAX;  // Entonces el puntero saltará del mínimo al máximo
}
 if (newPos > ROTARYMAX) { // Solo si el puntero es mayor al Valor Máximo ->
 encoder.setPosition(ROTARYMIN / ROTARYSTEPS);
 newPos = ROTARYMIN;  // Entonces el puntero saltará del máximo al  mínimo.
 }
#endif
}

Qué te parece @surbyte sería una mejor forma o no haría gran diferencia

Prueba1.png

Prueba2.png

Hola
meda estos errores

C:\Users\Car127\Downloads\ProyectoControlAcuarioDM\CADUSA1\CADUSA1.ino: In function 'void ImprimeFecha()':

CADUSA1:354: error: too many arguments to function 'void printDigits(int)'

 printDigits(now.day(), DEC);  // Imprime el día

                           ^

C:\Users\Car127\Downloads\ProyectoControlAcuarioDM\CADUSA1\CADUSA1.ino:330:6: note: declared here

void printDigits(int digits) {  // Esta función agrega un cero a dígitos menores a 10

    ^

CADUSA1:356: error: too many arguments to function 'void printDigits(int)'

 printDigits(now.month(), DEC);  // Imprime el mes

                             ^

C:\Users\Car127\Downloads\ProyectoControlAcuarioDM\CADUSA1\CADUSA1.ino:330:6: note: declared here

void printDigits(int digits) {  // Esta función agrega un cero a dígitos menores a 10

    ^

exit status 1
too many arguments to function 'void printDigits(int)'

Ok, funcionando

Muy complicado aunque funciona, porque no usan sprintf

void ImprimeFecha() {
  DateTime now = rtc.now();  // Consulta al RTC
  lcd.setCursor(0,0); // Fija el cursor en la primera línea 
  lcd.print(DiaDeSemana[now.dayOfTheWeek()]); // Imprime el día de la semana
  lcd.setCursor(10,0);
  printDigits(now.day(), DEC);  // Imprime el día
  lcd.print('/');   // Separador
  printDigits(now.month(), DEC);  // Imprime el mes
  lcd.print('/');  //  Separador
  lcd.print(now.year(), DEC);  // Imprime el año
}

void ImprimeHora() {
   DateTime now = rtc.now();   // Consulta el RTC
   lcd.setCursor(13,1);  // Fija cursor en 13,1
   lcd.write(1);  // Imprime el gráfico 
   lcd.print(':');
   printDigits(now.hour());  // Imprime hora
   lcd.print(':');
   printDigits(now.minute());  // Imprime minuto
   MinActual = now.hour()*60+now.minute();   // Se actualiza la variable MinActual que será usada para encender y apagar las luces del acuario. Su valor va de 0 a 1439.
}

Otra forma que evita el problmea de los dias/meses/horas/minutos de 1 digitos es esta

void ImprimeFecha() {
  char buffer[20];
  DateTime now = rtc.now();  // Consulta al RTC
  lcd.setCursor(0,0); // Fija el cursor en la primera línea 
  lcd.print(DiaDeSemana[now.dayOfTheWeek()]); // Imprime el día de la semana
  lcd.setCursor(10,0);
  sprintf(buffer,"%02d/%02d/%04d", now.day(),  now.month(), now.year());
  lcd.print(buffer);
}

void ImprimeHora() {
   char buffer[20];
   DateTime now = rtc.now();   // Consulta el RTC
   lcd.setCursor(13,1);  // Fija cursor en 13,1
   lcd.write(1);  // Imprime el gráfico 
   sprintf(buffer,"%02d:%02d:%02d", now.hout(), now.minute(), now.second());
   lcd.print(buffer);

   MinActual = now.hour()*60+now.minute();   // Se actualiza la variable MinActual que será usada para encender y apagar las luces del acuario. Su valor va de 0 a 1439.
}

En el void ImprimeTemp la parte del else faltaba los //

La parte del termometro con RTC tengo que probar con otro sketch para ver si funciona, ley por hay que en algunas versiones no funciona.

verificando eso sigo.

C:\Users\Car127\Downloads\ProyectoControlAcuarioDM\CADUSA1\CADUSA1.ino: In function 'void ImprimeTemp()':

CADUSA1:366: error: 'class RTC_DS3231' has no member named 'getTemperature'

     Tlamp = rtc.getTemperature(); // Asigna a Tlamp la temperatura del RTC

                 ^

C:\Users\Car127\Downloads\ProyectoControlAcuarioDM\CADUSA1\CADUSA1.ino: In function 'void MideTemperatura()':

CADUSA1:380: error: 'class RTC_DS3231' has no member named 'getTemperature'

      Tlamp = rtc.getTemperature();  // Se asigna a la variable Tlamp la temperatura del RTC

                  ^

C:\Users\Car127\Downloads\ProyectoControlAcuarioDM\CADUSA1\CADUSA1.ino: In function 'void overheating()':

CADUSA1:445: error: 'Termostato' was not declared in this scope

      Termostato();     // Corrobora el termostato para el calefactor

                 ^

CADUSA1:446: error: 'ControlCo2' was not declared in this scope

      ControlCo2();    // Comprueba si el Co2 debe estar activo 

                 ^

exit status 1
'class RTC_DS3231' has no member named 'getTemperature'

Es la biblioteca que uso no hace referencia a temperatura, me puedes adjuntar tu biblioteca del rtc

class RTC_DS3231' has no member named 'getTemperature'

car127:
Es la biblioteca que uso no hace referencia a temperatura, me puedes adjuntar tu biblioteca del rtc

RTClib

Es la misma que tenía, reclama lo mismo.
Adjunto lo que llevó

A mi me compila bien..

¿Porque el sketch ahora se llama CADUSA1.ino? ¿No tendrás en una misma carpeta CADUSA.ino y CADUSA1.ino?

no vario nada solo que no me funcionaba bien y lo baje denuevo despues me percate que era un mal contacto del encoder

la libreria del rtc de tu compu tiene el comando que falta al parecer revice los archivos .cpp y h y no aparece

Esta vivoooooo después de varios intentos lo logre, aprendi algo nuevo respecto a las librerías me voy a celebrar, mañana sigo

Pruebas con sensor temperatura DS18B20

La actualización de la información de corte de un cable demora aproximadamente 20seg
al desconectar cable rojo muestra información diferente no el de falla

La actualización de la información de temperatura demora aprox. 50 seg

ver forma de bajar tiempo

Adjunto imajen

Prueba de temperatura de RTC3231

Se toma temperatura ambiente y luego se acerca un cautin

La actualización de températura con demora

Menú Reloj modificando valores

Hola
el calefactor tiene que estar siempre encendido y trabajar así, si lo seteo a 25 grados se mantiene si sube se apaga si baja se enciende puede haber una variación de un grado, no entiendo porque en el dia una temperatura, horas que esta encendido , noche otra temperatura, la idea es tener una temperatura pareja y que no por un cambio de temperatura los peces se enfermen

Calefactor algo raro pasa

Falta algo

CADUSA1:107: error: 'TempHoraInicio' was not declared in this scope
CADUSA1:108: error: 'TempHoraFin' was not declared in this scope

No sigue igual y al quitar la energía no guarda lo configurado
adjunto archivo

linea 408,425,436,447,458 faltaba

read_but();  // Lee si opromimos el botón del encoder y enc_but pasa a valor 1.

Se mantiene lo observado primera configuración caracteres raros luego de 2 a 3 intentos se normaliza información Hora

Guarda configuración en Calefactor y CO2 al resetear y cortar energía

Realizadas las pruebas con código que adjuntaste

Prueba de calefactor con rele

temperatura 18° actual
se bajó hasta 9.9° sin actividad
aumento de temperatura hasta 60° sin actividad.

Configuración en el menú Calefactor
ON
Dia : 25°
Hora : 10:00 a 16:00
Noche : 18°

Hora toma de muestra 14:37

se probó con skech básico relé funcionando ok