#include <RTClib.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
//#include <LittleFS.h>
hw_timer_t *timer = NULL; // Temporizador 1 para parpadeo
hw_timer_t *timer1 = NULL; // Temporizador 2 para hibernacion
RTC_DS1307 rtc; // Definimo esl relog:
LiquidCrystal_I2C Pantalla (0x27, 16, 2 );// LCD pantalla dir0X27, fil 2, col 2
// Definimos tamaño de el teclado
const uint8_t Fils = 4;
const uint8_t Cols = 4;
char Teclas [Fils][Cols] = {{'1','2','3','A'}, // Definimos valores de cada tecla
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}};
// Definimos pines de trabajap del teclado
uint8_t PinCols [Cols] = {4, 0, 2, 15};
uint8_t PinFils [Fils] = {18, 5, 17, 16};
Keypad Teclado = Keypad(makeKeymap(Teclas), PinFils, PinCols, Fils, Cols);
// definiendo menus del programa
String MenuParametros[]= {"Dias Riego", "Eventos"};
String MenuOptions[]={"Elegir Prog","Editar Prog"};
String MenuEventos[]={"Agregar Eventos","Editar Eventos", "Borrar Eventos"};
String MenuProg[]={"Pr_01", "Pr_02", "Pr_03", "Pr_04", "Pr_05", "Pr_06","Pr_07", "Pr_08", "Pr_09", "Pr_10" };
//definimos tipo de Dato Para Horas, Horarios y Eventos
String DiaSe []={"DO", "LU", "MA", "MI", "JU", "VI", "SA"};
struct Parametro {uint8_t Hora; uint8_t Minutos; uint8_t Duracion;};
struct Evento {uint8_t Dia; Parametro Items; };
struct Seleccion {String Text; uint8_t Indi;};
struct EventoT {Evento Eve; uint32_t Tiempo;};
/******,*******************Programas de Prueva******************************/
uint8_t DiasV1[] ={0,1,2,3,4,5,6};
Parametro ParV1 []= {{6,30,5},{8,50,5},{20,30,5},{21,0,5}};
uint8_t DiasV2[] ={0,1,2,3,4,5,6};
Parametro ParV2 []= {{6,30,10},{7,0,10},{20,30,10},{21,0,10}};
uint8_t DiasV3[] ={0,1,2,3,4,5,6};
Parametro ParV3 []= {{6,30,5},{7,0,5},{20,30,5},{21,0,5}};
uint8_t DiasV4[] ={0,1,2,3,4,5,6};
Parametro ParV4 []= {{6,30,10},{7,0,10},{20,30,10},{21,0,10}};
uint8_t DiasV5[] ={0,1,2,3,4,5,6};
Parametro ParV5 []= {{6,30,5},{9,0,5},{20,30,5},{21,0,5}};
/****************************Cronogramas*********************************/
Evento CronogramaV1[28]={};
Evento CronogramaV2[28]={};
Evento CronogramaV3[28]={};
Evento CronogramaV4[28]={};
Evento CronogramaV5[28]={};
/*************************************************************************/
uint16_t Directorio[10][4];
uint8_t IndiProg = 0;
uint8_t Estado = 3;
void setup() {
// definimos los pines de control para las electrovalvulas
pinMode(34, OUTPUT);
digitalWrite(34, LOW);
pinMode(35, OUTPUT);
digitalWrite(35, LOW);
pinMode(32, OUTPUT);
digitalWrite(32, LOW);
pinMode(33, OUTPUT);
digitalWrite(33, LOW);
Serial.begin(115200);// Iniciamos la comunicasion serial
Pantalla.init(); // Iniciamos pantalla
/* Inicializando RTC Externo */
/***************************************************************************************/
if (rtc.begin()){
Serial.println("Inicializacion correcta del RTC");
Serial.flush();
}else{
Serial.println("Inicializacion fallida del RTC");
}
/* Inicializando RTC Interno */
/***************************************************************************************/
timer = timerBegin(10000);
if (timer == NULL){
Serial.println("Inicializasion del temporisador 1 fallida");
}
timer1 = timerBegin(10000);
if (timer1 == NULL){
Serial.println("Inicializasion del temporisador 2 fallida");
}
/* Montaje del sistema de archivos LittleFS */
/****************************************************************************************
if (LittleFS.begin()){
Serial.println("Arranque del sistema de archivos exitoso");
}else{
Serial.println("Falla al montar LittleFS Intentado formatear***");
if (LittleFS.format()){
Serial.println("LittleFS formateado con exito");
}else{
Serial.println("Error al formatear LittleFS");
}
}
/****************************************************************************************/
/* Cargado pantalla de bienvenida Mostrando Hora actual */
/****************************************************************************************/
//cargamos los programas
Cargar_Prog(DiasV1,ParV1,CronogramaV1,7,4);
Cargar_Prog(DiasV2,ParV2,CronogramaV2,7,4);
Cargar_Prog(DiasV3,ParV3,CronogramaV3,7,4);
Cargar_Prog(DiasV4,ParV4,CronogramaV4,7,4);
Cargar_Prog(DiasV5,ParV5,CronogramaV5,7,4);
Pantalla.backlight();
Pantalla.setCursor(3, 0);
Pantalla.print("Bienvenido");
Pantalla.setCursor(3, 1);
DateTime Tiempo = rtc.now();
Pantalla.print(Tiempo.timestamp(DateTime::TIMESTAMP_DATE));
delay(2000);
}
void loop() {
// definimos la maquin maquina de estados
switch (Estado){
case 0 :
Estado_0();
break;
case 1 :
Estado_1();
break;
case 2 :
Estado_2();
break;
case 3 :
Estado_3();
break;
case 4 :
Estado_4();
break;
case 5 :
Estado_5();
break;
case 6 :
Estado_6();
break;
case 7:
Estado_7();
break;
case 8:
Estado_8();
break;
case 9:
Estado_9();
break;
}
}
/* Estado # 0 (Seleccion de opciones de programas) */
/***********************************************************************************/
void Estado_0 (){
Serial.println("Este es el estado: 0");
Seleccion Option = FuntionMenu(MenuOptions,1);
Serial.println(Option.Text);
if (Option.Text == "Elegir Prog"){
Estado = 1;
}
if (Option.Text== "Editar Prog"){
Estado = 2;
}
}
/* Estado # 1 (Seleccion de programa para ejecutar) */
/***********************************************************************************/
void Estado_1 (){
Serial.println("Este es el estado: 1 (Eleccion del programa a ejecutar)");
Seleccion Option = FuntionMenu(MenuProg, 9);
//Serial.println(Option.Text);
if (Option.Text != "ESC"){
Pantalla.clear();
Pantalla.setCursor(0,0);
Pantalla.print("Elegiste: "+Option.Text);
Pantalla.setCursor(0,1);
Pantalla.print(" C:Si D:No ");
while (1){
char KeySiNo = Teclado.getKey();
if (KeySiNo == 'C'){
IndiProg = Option.Indi;
Estado = 3;
break;
}
if (KeySiNo == 'D'){
Estado = 1;
break;
}
}
}else{
Estado = 0;
}
}
/* Estado # 2 (Seleccion de programa para editar ) */
/***********************************************************************************/
void Estado_2 (){
Serial.println("Este es el estado: 2 (Eleccion del programa a editar)");
Seleccion Option = FuntionMenu(MenuProg, 9);
//Serial.println(Option.Text);
if (Option.Text != "ESC"){
Pantalla.clear();
Pantalla.setCursor(0,0);
Pantalla.print("Elegiste: "+Option.Text);
Pantalla.setCursor(0,1);
Pantalla.print(" C:Si D:No ");
while (1){
char KeySiNo = Teclado.getKey();
if (KeySiNo == 'C'){
IndiProg = Option.Indi;
Estado = 4;
break;
}
if (KeySiNo == 'D'){
Estado = 2;
break;
}
}
}else{
Estado = 0;
}
}
/* Estado # 3 () */
/***********************************************************************************/
void Estado_3(){
Serial.println("Este es el estado 3 Carga de programa");
DateTime Time = rtc.now();
rtc.set
uint32_t TiempoActual= Time.dayOfTheWeek()*24*60 + Time.hour()*60 + Time.minute();
// Buscamos y guardamos el proximo evento de cada cronograma
EventoT Proximos[5]={};
Proximos[0] = ProxEvento (TiempoActual, CronogramaV1,28);
Proximos[1] = ProxEvento (TiempoActual, CronogramaV2,28);
Proximos[2] = ProxEvento (TiempoActual, CronogramaV3,28);
Proximos[3] = ProxEvento (TiempoActual, CronogramaV4,28);
Proximos[4] = ProxEvento (TiempoActual, CronogramaV5,28);
// definimos el evento mas proximo a ejecutar
uint32_t MinVal = Proximos[0].Tiempo;
Evento MinProx = Proximos[0].Eve;
for (EventoT EvenT:Proximos){
MinVal = min(MinVal,EvenT.Tiempo);
if (MinVal==EvenT.Tiempo){
MinProx=EvenT.Eve;
}
}
// Establesemos la alarma para el evento mas proximo;
Pantalla.clear();
Pantalla.setCursor(0,0);
Pantalla.print(" V1: "+ DiaSe[MinProx.Dia]+" "+String(MinProx.Items.Hora)+ ":" + String(MinProx.Items.Minutos));
/* Pantalla.setCursor(0,1);
Pantalla.print(" V2: "+ DiaSe[ProxV2.Dia]+" "+String(ProxV2.Items.Hora)+ ":" + String(ProxV2.Items.Minutos));
*/
//Pantalla.print(DiaSe[Prox.Dia] +" "+String(Prox.Items.Hora) + ":" + String(Prox.Items.Minutos) +" "+String(Prox.Items.Duracion)+"min");
timerStart(timer);
timerStart(timer1);
delay(3000);
Serial.println(timerRead(timer));
Serial.println(timerRead(timer1));
bool Blink = 0;
bool X = 0;
while (X == 0){
if (timerRead(timer)>1000){
Blink= !Blink;
Serial.println(timerRead(timer));
Serial.println(timerRead(timer1));
timerRestart(timer);
Pantalla.setCursor(0,0);
if (Blink == 0){
Pantalla.print(">");
}
else {
Pantalla.print(" ");
}
}
if (Teclado.getKey()){
timerRestart(timer1);
}
if (timerReadSeconds(timer1)>30){
Pantalla.noBacklight();
}
}
Estado = 0;
}
/* Estado # 4 () */
/***********************************************************************************/
void Estado_4(){
Serial.println("Este es el estado 4()");
Seleccion OptionEdition = FuntionMenu(MenuParametros,1);
if (OptionEdition.Text != "ECS"){
if(OptionEdition.Indi == 0){
Estado=5;
}else {
Estado = 6;
}
}else{
Estado = 2;
}
}
/* Estado # 5 (Edision Dias) */
/***********************************************************************************/
void Estado_5(){
Serial.println("Este es el estado 5 (Eleccion dias de trabajo)");
String MenuDias[]= {"LU:", "MA:", "MI:", "JU:", "VI:", "SA:", "DO:"};
uint8_t dirCursor [7][2]={{0,0}, {4,0}, {8,0}, {12,0}, {0,1}, {4,1}, {8,1}};
uint8_t IndiDir=0;
boolean Dias[]{0,0,0,0,0,0,0};
boolean Blink;
Pantalla.clear();
for (uint8_t i = 0; i<7; i++){
Pantalla.setCursor(dirCursor[i][0], dirCursor[i][1]);
Pantalla.print(MenuDias[i]);
}
timerStart(timer);
while (1) {
char T = Teclado.getKey();
switch (T){
case 'B':
if (IndiDir<6){
Pantalla.setCursor(dirCursor[IndiDir][0],dirCursor[IndiDir][1]);
Pantalla.print(MenuDias[IndiDir]);
IndiDir++;
}
break;
case 'A':
if (IndiDir>0){
Pantalla.setCursor(dirCursor[IndiDir][0],dirCursor[IndiDir][1]);
Pantalla.print(MenuDias[IndiDir]);
IndiDir--;
}
break;
case 'C':
Serial.println(" ");
Dias[IndiDir] = !Dias[IndiDir];
if (Dias[IndiDir] == 0){
Pantalla.setCursor(dirCursor[IndiDir][0]+3,dirCursor[IndiDir][1]);
Pantalla.print(" ");
}else{
Pantalla.setCursor(dirCursor[IndiDir][0]+3,dirCursor[IndiDir][1]);
Pantalla.print(">");
}
for (boolean D: Dias){
Serial.print(D);
}
break;
case 'D':
Pantalla.clear();
Pantalla.setCursor(0,0);
Pantalla.print("Guardar cambios?");
Pantalla.setCursor(0,1);
Pantalla.print(" C:Si D:No ");
timerStop(timer);
timerRestart(timer);
while (1){
char KeySiNo = Teclado.getKey();
if (KeySiNo == 'C'){
Estado = 4;
break;
}
if (KeySiNo == 'D'){
Estado = 2;
break;
}
}
}
if (timerRead(timer)>1000){
Blink= !Blink;
timerRestart(timer);
Pantalla.setCursor(dirCursor[IndiDir][0],dirCursor[IndiDir][1]);
if (Blink == 0){
Pantalla.print(MenuDias[IndiDir]);
}
else {
Pantalla.print(" ");
}
}
}
}
/* Estado # 6 (Seleccion de opcion eventos) */
/***********************************************************************************/
void Estado_6(){
Serial.println("Este es el estado 6 (Seleccion de opciones Eventos)");
Seleccion OptionEvent= FuntionMenu(MenuEventos,2);
if (OptionEvent.Text != "ESC"){
if (OptionEvent.Indi == 0){
Estado = 7;
}
if (OptionEvent.Indi == 1){
Estado = 8;
}
if (OptionEvent.Indi == 2){
Estado = 9;
}
}
}
/* Estado # 7 (Crear eventos) */
/***********************************************************************************/
void Estado_7(){
Serial.println("Este es el estado 7 (Crear Eventos)");
uint8_t Cursor1=0;
const uint8_t DirTiempo[]={9,10,12,13};
uint8_t Indi= 0;
uint8_t Cursor2 =9;
char Valores []={'H','H','M','M'};
Pantalla.clear();
Pantalla.setCursor(0,0);
Pantalla.print(">Inicio|");
Pantalla.setCursor(0,1);
Pantalla.print(" Tiempo|");
while (1) {
char Key6= Teclado.getKey();
switch(Key6){
case 'B':
if (Cursor1 == 0){
Pantalla.setCursor(0,Cursor1);
Pantalla.print(" ");
Cursor1=1;
Pantalla.setCursor(0,Cursor1);
Pantalla.print(">");
}
break;
case 'A':
if (Cursor1 == 1){
Pantalla.setCursor(0,Cursor1);
Pantalla.print(" ");
Cursor1=0;
Pantalla.setCursor(0,Cursor1);
Pantalla.print(">");
}
break;
case 'C':
Pantalla.setCursor(9,1);
Pantalla.print("^");
Pantalla.setCursor(9,0);
if (Cursor1 == 0){
Pantalla.print("HH:MM");
}else{
Pantalla.print("MM:SS");
}
while(1){
char Key7 = Teclado.getKey();
if (Key7=='0'||Key7=='1'||Key7=='2'||Key7=='3'||Key7=='4'||Key7=='5'||Key7=='6'||Key7=='7'||Key7=='8'||Key7=='9'){
if (Cursor1 == 0) {
switch(Indi){
case 0:
if (Key7=='0'||Key7=='1'||Key7=='2'){
EscribirNum(Cursor2,DirTiempo,Indi,Key7,Valores);
}
break;
case 1:
Serial.println(Valores[0]);
if (Valores[0]=='2'){
if(Key7=='0'||Key7=='1'||Key7=='2'||Key7=='3'){
EscribirNum(Cursor2,DirTiempo,Indi,Key7,Valores);
}
}else{
EscribirNum(Cursor2,DirTiempo,Indi,Key7,Valores);
}
break;
case 2:
if (Key7=='0'||Key7=='1'||Key7=='2'||Key7=='3'||Key7=='4'||Key7=='5'){
EscribirNum(Cursor2,DirTiempo,Indi,Key7,Valores);
}
break;
case 3:
EscribirNum(Cursor2,DirTiempo,Indi,Key7,Valores);
break;
}
}else{
EscribirNum(Cursor2,DirTiempo,Indi,Key7,Valores);
}
}
if (Key7 =='B'){
Cursor2=DirTiempo[Indi];
Pantalla.setCursor(Cursor2,1);
Pantalla.print(" ");
if (Indi>2){Indi=0;}
else{Indi++;}
Cursor2 = DirTiempo[Indi];
Pantalla.setCursor(Cursor2,1);
Pantalla.print('^');
}
if (Key7 =='A'){
Cursor2=DirTiempo[Indi];
Pantalla.setCursor(Cursor2,1);
Pantalla.print(" ");
if (Indi<1){Indi=3;}
else{Indi--;}
Cursor2 = DirTiempo[Indi];
Pantalla.setCursor(Cursor2,1);
Pantalla.print('^');
}
}
}
}
}
/* Estado # 8 (Editar eventos) */
/***********************************************************************************/
void Estado_8 (){
Serial.println("Este es el estado 8 (Editar eventos)");
while(1){}
}
/* Estado # 9(Borrar eventos) */
/***********************************************************************************/
void Estado_9 (){
Serial.println("Este es el estado 9 (Borra eventos)");
while(1){}
}
/* Funcion seleccion de menu */
/************************************************************************************/
Seleccion FuntionMenu(String Menu[], uint8_t NumOptions){
boolean X = 0;
uint8_t Cursor = 0;
uint8_t Indice = 0;
Seleccion Options ;
Pantalla.clear();
for (uint8_t i = 0;i <= 1;i++){
Pantalla.setCursor(0, i);
Pantalla.print(" " + Menu[i]);
}
Pantalla.setCursor(0, 0);
Pantalla.print(">");
while (X ==0 ){
char Key = Teclado.getKey();
switch (Key){
case 'B':
if (Cursor == 1 && Indice<NumOptions){
Pantalla.setCursor(1,0);
Pantalla.print(" ");
Pantalla.setCursor(1, 1);
Pantalla.print(" ");
Pantalla.setCursor(1, 0);
Pantalla.print(Menu[Indice]);
Pantalla.setCursor(1, 1);
Pantalla.print(Menu[Indice+1]);
Indice++;
}
if (Cursor == 0){
Pantalla.setCursor(0, Cursor++);
Pantalla.print(" ");
Pantalla.setCursor(0, Cursor);
Pantalla.print(">");
Indice++;
}
break;
case 'A':
if (Cursor == 0 && Indice > 0){
Pantalla.setCursor(1,0);
Pantalla.print(" ");
Pantalla.setCursor(1, 1);
Pantalla.print(" ");
Pantalla.setCursor(1, 0);
Pantalla.print(Menu[Indice-1]);
Pantalla.setCursor(1, 1);
Pantalla.print(Menu[Indice]);
Indice--;
}
if (Cursor == 1){
Pantalla.setCursor(0, Cursor--);
Pantalla.print(" ");
Pantalla.setCursor(0, Cursor);
Pantalla.print(">");
Indice--;
}
break;
case 'C':
//Serial.println("Opcion: "+Menu[Indice]+" Indice: " +String(Indice));
X = 1;
Options.Text = Menu[Indice];
Options.Indi = Indice;
return Options;
break;
case 'D':
//Serial.println("ESC Indice: "+String(Indice));
X = 1;
Options.Text ="ESC";
Options.Indi = Indice;
return Options;
break;
}
}
}
/* Funcion Escribir y guaradar numeros */
/************************************************************************************/
void EscribirNum (uint8_t &Cursor2,const uint8_t DirTiempo[], uint8_t &Indi,char Key7,char Valores []){
Valores [Indi]=Key7;
Cursor2 = DirTiempo[Indi];
Pantalla.setCursor(Cursor2,0);
Pantalla.print(Key7);
Pantalla.setCursor(Cursor2,1);
Pantalla.print(" ");
if (Indi>2){Indi=0;}
else{Indi++;}
Serial.print(Indi);
Cursor2 = DirTiempo[Indi];
Pantalla.setCursor(Cursor2,1);
Pantalla.print("^");
}
/*********************************Cargara Programas**********************************/
void Cargar_Prog(uint8_t Dias[],Parametro Par[], Evento Cronograma[], uint8_t NumDias, uint8_t NumPar){
uint8_t I = 0;
for (uint8_t i = 0; i < NumDias; i++){
for (uint8_t j = 0; j < NumPar; j++){
Cronograma[I++]={Dias[i],{Par[j]}};
}
}
}
/*******************************Determina el Proximo Evento*************************/
EventoT ProxEvento(uint32_t TiempoActual,Evento Crono[], uint8_t NumEventos){
EventoT ProxT = {};
Evento Prox = Crono[0];
uint32_t MinutosE = Crono[0].Dia*24*60 + Crono[0].Items.Hora*60 + Crono[0].Items.Minutos;
for (uint8_t i = 0; i < NumEventos; i++){
MinutosE = Crono[i].Dia*24*60 + Crono[i].Items.Hora*60 + Crono[i].Items.Minutos;
if (MinutosE >= TiempoActual){
Prox= Crono[i];
break;
}
}
ProxT.Eve = Prox;
ProxT.Tiempo = MinutosE;
return ProxT;
}