#include <WiFi.h>
#include <time.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define SCREEN_ADDRESS 0x3C
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
const char* ssid = "Wokwi-GUEST";
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 0;
const int daylightOffset_sec = -10800; // GMT+5:30
int highlightedField = 1; // 1 for hour, 2 for minute, 3 for hour off, 4 for minute off, 5 for state, 6 for use schedule
float sizeoftext = 1;
const int ROWS = 2;
const int COLS = 4;
int rowPins[ROWS] = { 12, 14 }; // Pinos para as linhas
int colPins[COLS] = { 27, 26, 25, 33 }; // Pinos para as colunas
// Definição dos caracteres do teclado
char keys[ROWS][COLS] = {
{ 'L', 'R', 'U', 'D' },
{ '1', '2', '3', '4' }
};
// Pinos dos LEDs
const int numLeds = 8;
int ledPins[numLeds] = { 2, 4, 5, 15, 16, 17, 18, 19 };
// Matriz para armazenar as informações dos LEDs
int ledInfo[7][numLeds] = {
{1, 2, 3, 4, 5, 6, 7, 8}, // Número do LED
{23, 23, 18, 18, 18, 18, 18, 18}, // Hora de ligar
{04, 03, 0, 0, 0, 0, 0, 0}, // Minuto de ligar
{19, 19, 19, 19, 19, 19, 19, 19}, // Hora de desligar
{0, 0, 0, 0, 0, 0, 0, 0}, // Minuto de desligar
{1, 0, 1, 0, 0, 1, 1, 0}, // Usar horários (1 para sim, 0 para não)
{0, 0, 0, 0, 0, 0, 0, 0} // Estado atual (1 para ligado, 0 para desligado)
};
void setup() {
Serial.begin(115200);
// Connect to Wi-Fi
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected.");
// Initialize and get the time
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
// Configura o tamanho da fonte para diminuir o texto
display.setTextSize(sizeoftext);
// Configura os pinos do teclado como INPUT_PULLUP
for (int i = 0; i < COLS; i++) {
pinMode(colPins[i], INPUT_PULLUP);
}
// Configura os pinos dos LEDs como OUTPUT e inicializa todos desligados
for (int i = 0; i < numLeds; i++) {
pinMode(ledPins[i], OUTPUT);
digitalWrite(ledPins[i], LOW);
}
}
unsigned long lastKeyPressTime = 0;
bool isMenu1Active = true;
int currentSelectedLed = 0;
int currentEditingField = 1; // 1 for hour, 2 for minute
void loop() {
unsigned long currentTime = millis();
// Check if 10 seconds have elapsed since the last key press
if (currentTime - lastKeyPressTime >= 10000) {
isMenu1Active = true; // Go back to menu1
}
display.clearDisplay();
// Lê o teclado
char key = readKeypad();
if (key != 0) {
lastKeyPressTime = currentTime; // Update the last key press time
Serial.print("Tecla pressionada: ");
Serial.println(key);
// Check if the "L" or "R" key is pressed to switch menus only in menu1
if (isMenu1Active && (key == 'L' || key == 'R')) {
isMenu1Active = !isMenu1Active;
currentSelectedLed = 0; // Reset the selected LED when switching to menu1
currentEditingField = 1; // Reset to editing the hour of LED ON when entering menu2
}
// Update the highlight based on the pressed key
updateHighlight(key);
// Update LED states based on buttons 1, 2, 3, and 4 in menu1
if (isMenu1Active && (key == '1' || key == '2' || key == '3' || key == '4')) {
int buttonIndex = key - '1'; // Convert the button number to index (0-3)
// Toggle LED state for the selected LED
ledInfo[6][buttonIndex] = !ledInfo[6][buttonIndex];
// Update the LED pin state
digitalWrite(ledPins[buttonIndex], ledInfo[6][buttonIndex] ? HIGH : LOW);
}
}
if (isMenu1Active) {
DrawMenu01();
} else {
drawMenu2();
}
// Atualiza o estado dos LEDs com base nos horários
updateLeds();
display.display();
delay(100);
}
//-----------------------------------------------------------------------------------
void drawTextWithHighlight(Adafruit_SSD1306& display, bool isHighlighted, int field, const char* text) {
if (isHighlighted && field == highlightedField) {
display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); // Texto em preto com fundo branco
} else {
display.setTextColor(SSD1306_WHITE, SSD1306_BLACK); // Texto em branco com fundo preto
}
display.print(text);
display.setTextColor(SSD1306_WHITE); // Restaura a cor padrão (branco)
}
void drawLineInFirstColumn(int16_t y) {
display.drawLine(0, y - 2, SCREEN_WIDTH / 2, y - 2, SSD1306_WHITE);
}
void drawLineInSecondColumn(int16_t y) {
display.drawLine(SCREEN_WIDTH / 2, y - 2, SCREEN_WIDTH, y - 2, SSD1306_WHITE);
}
void DrawMenu01() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("Failed to obtain time");
return;
}
char currentTime[20];
sprintf(currentTime, "%02d:%02d:%02d", timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
display.setCursor(0, 0);
display.print("Hora atual:");
display.setCursor(0, 8);
display.print(currentTime);
for (int i = 0; i < numLeds; i += 2) {
int ledNumber1 = ledInfo[0][i];
bool currentState1 = ledInfo[6][i];
int hourOn1 = ledInfo[1][i];
int minuteOn1 = ledInfo[2][i];
int hourOff1 = ledInfo[3][i];
int minuteOff1 = ledInfo[4][i];
bool useSchedule1 = ledInfo[5][i];
int ledNumber2 = ledInfo[0][i + 1];
bool currentState2 = ledInfo[6][i + 1];
int hourOn2 = ledInfo[1][i + 1];
int minuteOn2 = ledInfo[2][i + 1];
int hourOff2 = ledInfo[3][i + 1];
int minuteOff2 = ledInfo[4][i + 1];
bool useSchedule2 = ledInfo[5][i + 1];
char ledNumberStr1[8];
sprintf(ledNumberStr1, "L%d_", ledNumber1);
char ledNumberStr2[8];
sprintf(ledNumberStr2, "L%d_", ledNumber2);
display.setCursor(0, 20 + i * 5);
// Draw a line over the text if "usar horarios" is off
if (!useSchedule1) {
drawLineInFirstColumn(24 + i * 5);
}
display.print(ledNumberStr1);
display.print(currentState1 ? "O" : "X");
display.print(" ");
int currentMinutes = timeinfo.tm_hour * 60 + timeinfo.tm_min;
// Calculate the remaining time to the next change in state (ON/OFF) for LED 1
int remainingMinutes1;
if (currentState1) {
remainingMinutes1 = hourOff1 * 60 + minuteOff1 - currentMinutes;
} else {
remainingMinutes1 = hourOn1 * 60 + minuteOn1 - currentMinutes;
}
// Normalize the remaining time to handle the case when it crosses midnight
if (remainingMinutes1 < 0) {
remainingMinutes1 += 24 * 60;
}
int remainingHours1 = remainingMinutes1 / 60;
remainingMinutes1 %= 60;
// Display the remaining time with two digits for both hours and minutes
display.printf("%02d:%02d", remainingHours1, remainingMinutes1);
display.print("|");
// Draw a line over the text if "usar horarios" is off
if (!useSchedule2) {
drawLineInSecondColumn(24 + i * 5);
}
display.print(ledNumberStr2);
display.print(currentState2 ? "O" : "X");
display.print(" ");
// Calculate the remaining time to the next change in state (ON/OFF) for LED 2
int remainingMinutes2;
if (currentState2) {
remainingMinutes2 = hourOff2 * 60 + minuteOff2 - currentMinutes;
} else {
remainingMinutes2 = hourOn2 * 60 + minuteOn2 - currentMinutes;
}
// Normalize the remaining time to handle the case when it crosses midnight
if (remainingMinutes2 < 0) {
remainingMinutes2 += 24 * 60;
}
int remainingHours2 = remainingMinutes2 / 60;
remainingMinutes2 %= 60;
// Display the remaining time with two digits for both hours and minutes
display.printf("%02d:%02d", remainingHours2, remainingMinutes2);
}
}
char readKeypad() {
// Matriz de caracteres do teclado
char keymap[ROWS][COLS] = {
{ 'L', 'R', 'U', 'D' },
{ '1', '2', '3', '4' }
};
// Define as linhas como OUTPUT e colunas como INPUT_PULLUP
for (int i = 0; i < ROWS; i++) {
pinMode(rowPins[i], OUTPUT);
digitalWrite(rowPins[i], LOW);
}
for (int j = 0; j < COLS; j++) {
pinMode(colPins[j], INPUT_PULLUP);
}
// Verifica as teclas pressionadas
char key = 0;
for (int i = 0; i < ROWS; i++) {
digitalWrite(rowPins[i], HIGH);
for (int j = 0; j < COLS; j++) {
if (digitalRead(colPins[j]) == LOW) {
key = keymap[i][j];
break;
}
}
digitalWrite(rowPins[i], LOW);
if (key != 0) break;
}
// Retorna a tecla pressionada (ou 0 se nenhuma tecla for pressionada)
return key;
}
void updateLeds() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("Failed to obtain time");
return;
}
int currentHour = timeinfo.tm_hour;
int currentMinute = timeinfo.tm_min;
int currentSecond = timeinfo.tm_sec;
for (int i = 0; i < numLeds; i++) {
int hourOn = ledInfo[1][i];
int minuteOn = ledInfo[2][i];
int hourOff = ledInfo[3][i];
int minuteOff = ledInfo[4][i];
bool useSchedule = ledInfo[5][i];
bool currentState = ledInfo[6][i];
// Verificar se o LED está no horário de ligar e usarHorarios estiver habilitado
if (useSchedule && currentHour == hourOn && currentMinute == minuteOn && currentSecond<2) {
currentState = 1;
}
// Verificar se o LED está no horário de desligar e usarHorarios estiver habilitado
if (useSchedule && currentHour == hourOff && currentMinute == minuteOff && currentSecond<2) {
currentState = 0;
}
// Atualizar o estado na matriz
ledInfo[6][i] = currentState;
// Atualizar o estado do LED correspondente
digitalWrite(ledPins[i], currentState ? HIGH : LOW);
}
}
// Function to navigate to the previous LED
void goToPreviousLed() {
currentSelectedLed = (currentSelectedLed - 1 + numLeds) % numLeds;
highlightedField = 1; // Reset to editing the hour of LED ON
}
void goToNextLed() {
currentSelectedLed = (currentSelectedLed + 1) % numLeds;
highlightedField = 1; // Reset to editing the hour of LED ON
}
void drawMenu2() {
display.clearDisplay();
for (int i = 0; i < numLeds; i++) {
bool isHighlighted = (i == currentSelectedLed);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, i * 8);
display.print("l.");
display.print(ledInfo[0][i]);
display.print(" ");
char hourOnStr[3];
sprintf(hourOnStr, "%02d", ledInfo[1][i]);
drawTextWithHighlight(display, isHighlighted, 1, hourOnStr);
display.print(":");
char minuteOnStr[3];
sprintf(minuteOnStr, "%02d", ledInfo[2][i]);
drawTextWithHighlight(display, isHighlighted, 2, minuteOnStr);
display.print(" | ");
char hourOffStr[3];
sprintf(hourOffStr, "%02d", ledInfo[3][i]);
drawTextWithHighlight(display, isHighlighted, 3, hourOffStr);
display.print(":");
char minuteOffStr[3];
sprintf(minuteOffStr, "%02d", ledInfo[4][i]);
drawTextWithHighlight(display, isHighlighted, 4, minuteOffStr);
display.print(" ");
drawTextWithHighlight(display, isHighlighted, 5, ledInfo[5][i] ? "O" : "X");
display.print(" ");
drawTextWithHighlight(display, isHighlighted, 6, ledInfo[6][i] ? "O" : "X");
}
display.display();
}
void updateHighlight(char key) {
if (isMenu1Active) {
if (key == 'U') {
currentSelectedLed = (currentSelectedLed - 1 + numLeds) % numLeds;
} else if (key == 'D') {
currentSelectedLed = (currentSelectedLed + 1) % numLeds;
}
} else {
if (key == 'L') {
if (currentEditingField == 1) {
// Navigate to the next LED if editing the hour of LED ON
goToPreviousLed();
currentEditingField = 6; // Reset to editing the "usar horarios" field for the new LED
} else if (currentEditingField == 2) {
// Navigate to the hour of LED ON if editing the minute of LED ON
currentEditingField = 1;
} else if (currentEditingField == 3) {
// Navigate to the minute of LED ON if editing the hour of LED OFF
currentEditingField = 2;
} else if (currentEditingField == 4) {
// Navigate to the hour of LED OFF if editing the minute of LED OFF
currentEditingField = 3;
} else if (currentEditingField == 5) {
// Navigate to the minute of LED OFF if editing the "estado" field
currentEditingField = 4;
} else if (currentEditingField == 6) {
// Navigate to the "estado" field if editing the "usar horarios" field
currentEditingField = 5;
}
} else if (key == 'R') {
if (currentEditingField == 1) {
// Navigate to the minute of LED ON if editing the hour of LED ON
currentEditingField = 2;
} else if (currentEditingField == 2) {
// Navigate to the hour of LED OFF if editing the minute of LED ON
currentEditingField = 3;
} else if (currentEditingField == 3) {
// Navigate to the minute of LED OFF if editing the hour of LED OFF
currentEditingField = 4;
} else if (currentEditingField == 4) {
// Navigate to the "estado" field if editing the minute of LED OFF
currentEditingField = 5;
} else if (currentEditingField == 5) {
// Navigate to the "usar horarios" field if editing the "estado" field
currentEditingField = 6;
} else if (currentEditingField == 6) {
// Navigate to the next LED if editing the "usar horarios" field
goToNextLed();
currentEditingField = 1; // Reset to editing the hour of LED ON for the new LED
}
} else if (key == 'U') {
// Increase the value of the current editing field
if (currentEditingField == 1) {
ledInfo[1][currentSelectedLed] = (ledInfo[1][currentSelectedLed] + 1) % 24; // Hour of LED ON
} else if (currentEditingField == 2) {
ledInfo[2][currentSelectedLed] = (ledInfo[2][currentSelectedLed] + 1) % 60; // Minute of LED ON
} else if (currentEditingField == 3) {
ledInfo[3][currentSelectedLed] = (ledInfo[3][currentSelectedLed] + 1) % 24; // Hour of LED OFF
} else if (currentEditingField == 4) {
ledInfo[4][currentSelectedLed] = (ledInfo[4][currentSelectedLed] + 1) % 60; // Minute of LED OFF
} else if (currentEditingField == 5) {
ledInfo[5][currentSelectedLed] = !ledInfo[5][currentSelectedLed]; // Toggle "estado"
} else if (currentEditingField == 6) {
ledInfo[6][currentSelectedLed] = !ledInfo[6][currentSelectedLed]; // Toggle "usar horarios"
}
} else if (key == 'D') {
// Decrease the value of the current editing field
if (currentEditingField == 1) {
ledInfo[1][currentSelectedLed] = (ledInfo[1][currentSelectedLed] - 1 + 24) % 24; // Hour of LED ON
} else if (currentEditingField == 2) {
ledInfo[2][currentSelectedLed] = (ledInfo[2][currentSelectedLed] - 1 + 60) % 60; // Minute of LED ON
} else if (currentEditingField == 3) {
ledInfo[3][currentSelectedLed] = (ledInfo[3][currentSelectedLed] - 1 + 24) % 24; // Hour of LED OFF
} else if (currentEditingField == 4) {
ledInfo[4][currentSelectedLed] = (ledInfo[4][currentSelectedLed] - 1 + 60) % 60; // Minute of LED OFF
} else if (currentEditingField == 5) {
ledInfo[5][currentSelectedLed] = !ledInfo[5][currentSelectedLed]; // Toggle "estado"
} else if (currentEditingField == 6) {
ledInfo[6][currentSelectedLed] = !ledInfo[6][currentSelectedLed]; // Toggle "usar horarios"
}
}
// After updating the values, set the highlightedField to the currentEditingField
highlightedField = currentEditingField;
}
}