/**
Proyecto Arquitectura Computacional - Microcontroladores
Hecho por:
cristian ortega
santiago bastidas
edwin ordoñes
**/
#include <LiquidMenu.h>
#include "Average.h"
#include "melody.h"
#include <LiquidCrystal.h>
#include <Keypad.h>
#include <DHT.h>
#include "Button.h"
#include "StateMachineLib.h"
#include "AsyncTaskLib.h"
#include <LiquidMenu.h>
// VARIABLES*********************************
#define PASSWORD_ATTEMPTS 3
#define DEF_TMP_HIGH 40
#define DEF_TMP_LOW 10
#define DEF_LUZ_HIGH 650
#define DEF_LUZ_LOW 20
#define DEF_HALL 600
#define DEF_IR 0
// Variables para la contraseña
struct buffer {
static const int size = 16;
char str[size + 1];
byte len = 0;
void push(char chr) {
if (len == size) return;
str[len++] = chr;
}
void clear() {
for (size_t i = 0; i < this->len; i++) {
str[i] = 0;
}
len = 0;
}
bool isFull() {
return len == size;
}
char lastCharacter() {
return len == 0 ? 0 : str[len - 1];
}
} keypadBuffer;
const byte password_len = 4;
const char password[password_len + 1] = "4444";
byte password_attempts;
// Variables de la configuaracion de los eventos
float tmp_high = DEF_TMP_HIGH;
float tmp_low = DEF_TMP_LOW;
int16_t luz_high = DEF_LUZ_HIGH;
int16_t luz_low = DEF_LUZ_LOW;
int16_t hall_high = DEF_HALL;
int16_t ir_low = DEF_IR;
// Variables de Monitoreo
float T = 0; /* !< Temperatura */
int16_t H = 0; /* !< Humedad */
int16_t L = 0; /* !< Luz */
int16_t HALL = 0; /* !< Hall */
int16_t IR_SENSOR = 0; /* !< Sensor Infrarrojo */
Average<float> temperatura(5);
Average<int16_t> humedad(5);
Average<int16_t> luz(5);
Average<int16_t> hall(5);
Average<int16_t> ir_sensor(5);
char messageAlarma[17];
char messageAlerta[17];
// Enums de la maquina de estados
enum State {
Inicio = 0,
Config = 1,
// Alerta = 1,
MonitoreoAmbiental = 2,
Bloqueado = 3,
MonitoreoEventos = 4,
Alarma = 5,
};
enum Input {
Unknown = 0,
ClaveCorrecta = 2,
BotonPresionado = 1,
BloqueoSistema = 3,
Timeout = 4,
Umbral = 5
};
Input input = Unknown;
// MAQUINA DE ESTADOS**************************************
void onEnteringInicio();
void onLeavingInicio();
void onEnteringConfig();
void onLeavingConfig();
void onEnteringMAmbiental();
void onLeavingMAmbiental();
void onEnteringMEventos();
void onLeavingMEventos();
void onEnteringBloqueado();
void onLeavingBloqueado();
void onEnteringAlarma();
void onLeavingAlarma();
boolean compareAndResetInput(Input inputIn);
StateMachine stateMachine(6, 12);
void setupStateMachine() {
// Inicio
stateMachine.AddTransition(Inicio,MonitoreoAmbiental , []() {
return compareAndResetInput(Input::ClaveCorrecta);
});
stateMachine.AddTransition(Inicio, Bloqueado, []() {
return compareAndResetInput(Input::BloqueoSistema);
});
//Config
stateMachine.AddTransition(Config, MonitoreoAmbiental, []() {
return compareAndResetInput(BotonPresionado);
});
//Monitoreo Ambiental
stateMachine.AddTransition(MonitoreoAmbiental, Config, []() {
return compareAndResetInput(BotonPresionado);
});
stateMachine.AddTransition(MonitoreoAmbiental, Alarma, []() {
return compareAndResetInput(Umbral);
});
stateMachine.AddTransition(MonitoreoAmbiental, MonitoreoEventos, []() {
return compareAndResetInput(Timeout);
});
// Bloqueado
stateMachine.AddTransition(Bloqueado, Inicio, []() {
return compareAndResetInput(Timeout);
});
//Monitoreo Eventos
stateMachine.AddTransition(MonitoreoEventos, Config, []() {
return compareAndResetInput(BotonPresionado);
});
stateMachine.AddTransition(MonitoreoEventos, MonitoreoAmbiental, []() {
return compareAndResetInput(Timeout);
});
stateMachine.AddTransition(MonitoreoEventos, Alarma, []() {
return compareAndResetInput(Umbral);
});
//Alarma
stateMachine.AddTransition(Alarma, MonitoreoAmbiental, []() {
return compareAndResetInput(Timeout);
});
stateMachine.AddTransition(Alarma, Inicio, []() {
return compareAndResetInput(BotonPresionado);
});
stateMachine.SetOnEntering(Inicio, onEnteringInicio);
stateMachine.SetOnEntering(Config, onEnteringConfig);
stateMachine.SetOnEntering(MonitoreoAmbiental, onEnteringMAmbiental);
stateMachine.SetOnEntering(Bloqueado, onEnteringBloqueado);
stateMachine.SetOnEntering(MonitoreoEventos, onEnteringMEventos);
stateMachine.SetOnEntering(Alarma, onEnteringAlarma);
stateMachine.SetOnLeaving(Inicio, onLeavingInicio);
stateMachine.SetOnLeaving(Config, onLeavingConfig);
stateMachine.SetOnLeaving(MonitoreoAmbiental, onLeavingMAmbiental);
stateMachine.SetOnLeaving(Bloqueado, onLeavingBloqueado);
stateMachine.SetOnLeaving(MonitoreoEventos, onLeavingMEventos);
stateMachine.SetOnLeaving(Alarma, onLeavingAlarma);
}
// INPUT FUNCTION
boolean compareAndResetInput(Input inputIn) {
if (input == inputIn) {
input = Unknown;
return true;
}
return false;
}
// MICRO CONF ************************************
#define SENSOR_PIN 6 // Pin del sensor infrarrojo
#define DHT_TYPE DHT22
#define DHT_PIN 39
#define PHOTOCELL_PIN A0
#define BUZZER_PIN 7
#define HALL_PIN A1
#define LCD_RS 12
#define LCD_EN 11
#define LCD_D4 5
#define LCD_D5 4
#define LCD_D6 3
#define LCD_D7 2
#define LED_R 8
#define LED_G 9
#define LED_B 10
#define BUTTON_PIN 53
/* CONFIGURACION LCD */
LiquidCrystal lcd(LCD_RS, LCD_EN, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
/* CONFIGURACION DHT */
DHT dht(DHT_PIN, DHT_TYPE);
/* CONFIGURACION KEYPAD */
const byte KEYPAD_ROWS = 4;
const byte KEYPAD_COLS = 4;
char padKeys[KEYPAD_ROWS][KEYPAD_COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
byte keypadRowPins[KEYPAD_ROWS] = {22, 24, 26, 28}; //connect to the row pinouts of the keypad
byte keypadColPins[KEYPAD_COLS] = {30, 32, 34, 36}; //connect to the column pinouts of the keypad
Keypad customKeypad = Keypad( makeKeymap(padKeys), keypadRowPins, keypadColPins, KEYPAD_ROWS, KEYPAD_COLS);
/* CONFIGURACIÓN BOTON */
Button button(BUTTON_PIN, true);
// MENU_CONFIG*******************************************
void blankFunction() { return; }
/* CONFIGURACION DE LIQUID MENU*/
// LiquidLine line_tmp_high(0, 0, "TEMP_HIGH:", tmp_high);
// LiquidLine line_tmp_low (0, 1, "TEMP_LOW: ", tmp_low);
// LiquidLine line_luz_high(0, 1, "LUZ_HIGH: ", luz_high);
// LiquidLine line_luz_low (0, 1, "LUZ_LOW: ", luz_low);
// LiquidLine line_hall (0, 1, "HALL: ", hall_high);
LiquidLine line_reset (0, 1, "RESET");
//LiquidLine line_left(0, 1, "<");
//LiquidLine line_right(7, 1, ">");
LiquidScreen scrn_config;
LiquidLine status_tmp_m(0, 0, "Luz:", L);
LiquidLine status_hum_m(8, 0, "Hum:", H, "%");
LiquidLine status_luz_m(0, 1, "Temp:", T, "C");
LiquidScreen scrn_monitoreo_ambiental(status_tmp_m, status_hum_m, status_luz_m);
LiquidLine status_hall_m(0, 0, "Hall:", HALL);
LiquidLine status_if_m(0, 1, "If: ", IR_SENSOR);
LiquidScreen scrn_monitoreo_eventos(status_hall_m,status_if_m);
LiquidLine line_alarma(0, 0, "Precaucion");
LiquidLine status_alarma(0, 1, messageAlarma);
LiquidScreen scrn_alarma(line_alarma, status_alarma);
LiquidLine line_alerta(0, 0, "Precaucion");
LiquidLine status_alerta(0, 1, messageAlerta);
LiquidScreen scrn_alerta(line_alerta, status_alerta);
LiquidMenu mainMenu(lcd);
void setupLiquidMenu() {
scrn_config.add_line(line_tmp_high);
scrn_config.add_line(line_tmp_low);
scrn_config.add_line(line_luz_high);
scrn_config.add_line(line_luz_low);
scrn_config.add_line(line_hall);
scrn_config.add_line(line_reset);
line_tmp_high.attach_function(1, blankFunction);
line_tmp_low.attach_function(1, blankFunction);
line_luz_high.attach_function(1, blankFunction);
line_luz_low.attach_function(1, blankFunction);
line_hall.attach_function(1, blankFunction);
line_reset.attach_function(1, blankFunction);
line_tmp_high.set_decimalPlaces(1);
line_tmp_low.set_decimalPlaces(1);
scrn_config.set_displayLineCount(2);
mainMenu.add_screen(scrn_config);
mainMenu.add_screen(scrn_monitoreo_eventos);
mainMenu.add_screen(scrn_monitoreo_ambiental);
mainMenu.add_screen(scrn_alarma);
mainMenu.add_screen(scrn_alerta);
}
// TASK CONFIG***********************************
void controlTemperatura();
void controlHumedad();
void controlLuz();
void controlHall();
void onSeguridadAFK();
void inputTimeout();
void onUpdateMenu();
AsyncTask taskUpdateMenu(1000, true, onUpdateMenu);
AsyncTask taskTemperatura(1000, true, controlTemperatura);
AsyncTask taskHumedad(1000, true, controlHumedad);
AsyncTask taskLuz(1000, true, controlLuz);
AsyncTask taskHall(1000, true, controlHall);
AsyncTask taskIRSensor(1000, true,controlIRSensor);
AsyncTask taskTimeoutEventos(3000, false, inputTimeout);
AsyncTask taskTimeoutAmbiental(7000, false, inputTimeout);
AsyncTask taskTimeoutAlarma(4000, false, inputTimeout);
AsyncTask taskTimeoutInicioAFK(7000, false, onSeguridadAFK);
void controlTemperatura() {
T = temperatura.rolling(dht.readTemperature());
//mainMenu.update();
if (T > tmp_high) {
strcpy(messageAlarma, "'Ta Caliente");
input = Input::Umbral;
}
}
void controlHumedad() {
H = humedad.rolling(dht.readHumidity());
//mainMenu.update();
}
void controlLuz() {
L = luz.rolling(analogRead(PHOTOCELL_PIN));
//mainMenu.update();
if (L > luz_high) {
strcpy(messageAlarma, "'Ta Oscuro");
input = Input::Umbral;
}
}
void controlHall() {
HALL = hall.rolling(analogRead(HALL_PIN));
//mainMenu.update();
if (HALL > hall_high) {
strcpy(messageAlarma, "Hay Iman");
input = Input::Umbral;
}
}
void controlIF() {
HALL = hall.rolling(analogRead(HALL_PIN));
//mainMenu.update();
if (HALL > hall_high) {
strcpy(messageAlarma, "Hay Iman");
input = Input::BotonPresionado;
}
}
void controlIRSensor() {
IR_SENSOR = digitalRead(SENSOR_PIN);
if (IR_SENSOR == ir_low) {
strcpy(messageAlerta, "Algo Detectado");
input = Input::Umbral; // Activar alarma
setLED(0, 1, 0); // Encender LED verde
input = Input::BotonPresionado;
} else {
setLED(1, 0, 0);
}
}
void onSeguridadAFK() {
--password_attempts;
keypadBuffer.clear();
setLED(1, 1, 0);
lcd.clear();
lcd.print("Incorrecto");
delay(1000);
setLED(0, 0, 0);
lcd.clear();
lcd.print("Clave: ");
}
void inputTimeout() {
input = Timeout;
}
void onUpdateMenu() {
mainMenu.update();
}
/* FUNCIONES PREDECLARADAS */
void seguridad();
void menu();
void bloqueo();
void alarma();
void monitoreoAmbiental();
void monitoreoEventos();
template <typename T>
void changeVariableControl(T* variable, T step, char key, T lower_limit, T upper_limit);
/* SETUP ---------------------------------------------------------- */
void setup() {
// Inicializa los componentes necesarios
lcd.begin(16, 2);
dht.begin();
Serial.begin(9600);
// Inicializa el LED
pinMode(LED_R, OUTPUT);
pinMode(LED_G, OUTPUT);
pinMode(LED_B, OUTPUT);
setLED(0, 0, 0);
// Inicializa el menu del lcd
setupLiquidMenu();
// Inicializa la maquina de estados
Serial.println("Starting State Machine...");
setupStateMachine();
Serial.println("State Machine Started");
stateMachine.SetState(Inicio, false, true);
}
/* LOOP ---------------------------------------------------------- */
void loop() {
switch (stateMachine.GetState()) {
case State::Inicio: seguridad(); break;
case State::Config: menu(); break;
case State::MonitoreoAmbiental: monitoreoAmbiental(); break;
case State::MonitoreoEventos: monitoreoEventos(); break;
case State::Alarma: alarma(); break;
case State::Bloqueado: bloqueo(); break;
}
// Actualizar Maquina de Estados
stateMachine.Update();
}
// IMPLEMENTACION FUNCIONES
void seguridad() {
taskTimeoutInicioAFK.Update();
if (password_attempts == 0) {
input = BloqueoSistema;
return;
}
const char key = customKeypad.getKey();
if (!key) return;
if (key != 'A') {
keypadBuffer.push(key);
lcd.print('*');
if (!keypadBuffer.isFull()) return;
}
if (keypadBuffer.len == password_len && strncmp(password, keypadBuffer.str, password_len) == 0) {
setLED(0, 1, 0);
lcd.clear();
lcd.print("Correcto");
input = ClaveCorrecta; // <-- Input para la maquina de estados
} else {
--password_attempts;
setLED(0, 0, 1);
lcd.clear();
lcd.print("Incorrecto");
}
delay(1000);
setLED(0, 0, 0);
lcd.clear();
lcd.print("Clave: ");
keypadBuffer.clear();
}
void bloqueo() {
setLED(1, 0, 0);
lcd.setCursor(0, 0);
lcd.print("Sistema ");
lcd.setCursor(0, 1);
lcd.print("Bloqueado");
execute_melody(melodyBloqueo);
lcd.clear();
input = Input::Timeout;
}
void alarma() {
const char key = customKeypad.getKey();
taskTimeoutAlarma.Update();
taskTemperatura.Update();
taskHumedad.Update();
taskLuz.Update();
taskHall.Update();
taskIRSensor.Update();
if (key == '*') input = Input::BotonPresionado;
}
void menu() {
// lcd.print("alertaPru");
taskTimeoutAlarma.Update();
taskHumedad.Update();
taskLuz.Update();
taskHall.Update();
taskIRSensor.Update();
}
// void menu() {
// const char key = customKeypad.getKey();
// if (button.check() == LOW) input = Input::BotonPresionado;
// if (!key) return;
// switch (mainMenu.get_focusedLine()) {
// case 0: changeVariableControl<float>(&tmp_high, 0.5, key, tmp_low, 100); break;
// case 1: changeVariableControl<float>(&tmp_low, 0.5, key, -50, tmp_high); break;
// case 2: changeVariableControl<int16_t>(&luz_high, 10, key, luz_low, 1000); break;
// case 3: changeVariableControl<int16_t>(&luz_low, 10, key, 0, luz_high); break;
// case 4: changeVariableControl<int16_t>(&hall_high, 10, key, -1000, 1000); break;
// case 5:
// if (key == 'B') {
// tmp_high = DEF_TMP_HIGH;
// tmp_low = DEF_TMP_LOW;
// luz_high = DEF_LUZ_HIGH;
// luz_low = DEF_LUZ_LOW;
// hall_high = DEF_HALL;
// }
// break;
// }
// if (key == 'A') {
// mainMenu.switch_focus();
// }
// mainMenu.update();
// }
void monitoreoAmbiental() {
taskTemperatura.Update();
taskHumedad.Update();
taskLuz.Update();
taskHall.Update();
taskIRSensor.Update(); // Llamar a la función del sensor infrarrojo
taskTimeoutAmbiental.Update();
taskUpdateMenu.Update();
if (button.check() == LOW) input = Input::BotonPresionado;
}
void monitoreoEventos() {
taskTemperatura.Update();
taskHumedad.Update();
taskLuz.Update();
taskHall.Update();
taskIRSensor.Update();
taskTimeoutEventos.Update();
taskUpdateMenu.Update();
if (button.check() == LOW) input = Input::BotonPresionado;
}
template <typename T>
void changeVariableControl(T* variable, T step, char key, T lower_limit, T upper_limit) {
switch (key) {
case 'C':
if (*variable + step > upper_limit) return;
*variable += step;
break;
case 'D':
if (*variable - step < lower_limit) return;
*variable -= step;
break;
}
}
// MAQUINA DE ESTADOS**************************************
// ENTERING/LEAVING FUNCTIONS
void onEnteringInicio() {
Serial.println("Entering Inicio");
keypadBuffer.clear();
password_attempts = PASSWORD_ATTEMPTS;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Clave: ");
}
void onLeavingInicio() {
Serial.println("Leaving Inicio");
taskTimeoutInicioAFK.Stop();
}
void onEnteringConfig() {
Serial.println("Entering Configuracion");
mainMenu.change_screen(&scrn_config);
mainMenu.set_focusedLine(0);
mainMenu.update();
}
void onLeavingConfig() {
Serial.println("Leaving Configuracion");
}
void onEnteringMAmbiental() {
Serial.println("Entering Monitoreo Ambiental");
taskTemperatura.Start();
taskHumedad.Start();
taskLuz.Start();
taskHall.Start();
taskIRSensor.Start();
taskTimeoutAmbiental.Start();
taskUpdateMenu.Start();
mainMenu.change_screen(&scrn_monitoreo_ambiental);
mainMenu.update();
}
void onLeavingMAmbiental() {
Serial.println("Leaving Monitoreo Ambiental");
taskTemperatura.Stop();
taskHumedad.Stop();
taskLuz.Stop();
taskHall.Stop();
taskIRSensor.Stop();
taskTimeoutAmbiental.Stop();
taskUpdateMenu.Stop();
}
void onEnteringMEventos() {
Serial.println("Entering Monitoreo Eventos");
taskTemperatura.Start();
taskHumedad.Start();
taskLuz.Start();
taskHall.Start();
taskIRSensor.Start();
taskTimeoutEventos.Start();
taskUpdateMenu.Start();
mainMenu.change_screen(&scrn_monitoreo_eventos);
mainMenu.update();
}
void onLeavingMEventos() {
Serial.println("Leaving Monitoreo Eventos");
taskTemperatura.Stop();
taskHumedad.Stop();
taskLuz.Stop();
taskHall.Stop();
taskIRSensor.Stop();
taskTimeoutEventos.Stop();
taskUpdateMenu.Stop();
}
void onEnteringBloqueado() {
Serial.println("Entering Bloqueado");
}
void onLeavingBloqueado() {
Serial.println("Leaving Bloqueado");
setLED(0, 0, 0);
}
void onEnteringAlarma() {
Serial.println("Entering Alarma");
setLED(0, 0, 1);
tone(buzzer, 97, 4000);
taskTemperatura.Start();
taskHumedad.Start();
taskLuz.Start();
taskHall.Start();
taskIRSensor.Start(); // Iniciar la tarea del sensor infrarrojo
taskTimeoutAlarma.Start();
mainMenu.change_screen(&scrn_alarma);
mainMenu.update();
}
void onLeavingAlarma() {
Serial.println("Leaving Alarma");
taskTemperatura.Stop();
taskHumedad.Stop();
taskLuz.Stop();
taskHall.Stop();
taskIRSensor.Stop();
noTone(buzzer);
taskTimeoutAlarma.Stop();
setLED(0, 0, 0);
}
// Funciones para el sensor infrarrojo*********************
// funcion luces***************************************
void setLED(uint16_t red, uint16_t green, uint16_t blue) {
digitalWrite(LED_R, red);
digitalWrite(LED_G, green);
digitalWrite(LED_B, blue);
}