#include <WiFi.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <time.h>
#include <SevSeg.h>
#include <math.h>
// ===================== WIFI =====================
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// ================= DISPLAY TFT ==================
#define TFT_CS 5
#define TFT_RST 4
#define TFT_DC 2
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
// ================= DISPLAY 7 SEG ================
SevSeg sevseg;
// segmentos: A, B, C, D, E, F, G, DP
byte segmentPins[] = {12, 13, 15, 16, 17, 21, 22, 32};
// dígitos
byte digitPins[] = {33, 0, 1, 3};
// ================= LEDS =========================
#define LED_AZUL_1 25
#define LED_AZUL_2 26
#define LED_VERDE_1 27
#define LED_VERDE_2 14
// ================= NTP ==========================
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = -10800;
const int daylightOffset_sec = 0;
// ================= CONTROLE =====================
bool modoDeepWork = false;
String ultimaHora = "";
String ultimaData = "";
String ultimoStatus = "";
// ================================================
String diaSemana(int d) {
switch (d) {
case 0: return "Domingo";
case 1: return "Segunda";
case 2: return "Terca";
case 3: return "Quarta";
case 4: return "Quinta";
case 5: return "Sexta";
case 6: return "Sabado";
default: return "";
}
}
void centralizar(String txt, int y, int size, uint16_t cor) {
int16_t x1, y1;
uint16_t w, h;
tft.setTextSize(size);
tft.setTextColor(cor);
tft.getTextBounds(txt, 0, y, &x1, &y1, &w, &h);
int x = (tft.width() - w) / 2;
tft.setCursor(x, y);
tft.print(txt);
}
void telaBase() {
tft.fillScreen(ILI9341_BLACK);
tft.drawRect(10, 10, 220, 40, ILI9341_CYAN);
centralizar("* FOCUS GADGET *", 22, 2, ILI9341_YELLOW);
tft.drawRect(10, 60, 220, 60, ILI9341_WHITE);
tft.drawRect(10, 130, 220, 70, ILI9341_GREEN);
// caixa inferior maior
tft.drawRect(10, 205, 220, 115, ILI9341_DARKCYAN);
}
void conectarWiFi() {
WiFi.begin(ssid, password);
centralizar("Conectando...", 245, 2, ILI9341_CYAN);
while (WiFi.status() != WL_CONNECTED) {
delay(300);
}
tft.fillRect(20, 240, 200, 25, ILI9341_BLACK);
centralizar("WiFi OK", 245, 2, ILI9341_GREEN);
}
bool verificarDeepWork(int hora, int minuto) {
int atual = hora * 60 + minuto;
int inicio1 = 8 * 60;
int fim1 = 12 * 60;
int inicio2 = 13 * 60 + 30;
int fim2 = 18 * 60;
return ((atual >= inicio1 && atual < fim1) ||
(atual >= inicio2 && atual < fim2));
}
bool horarioWow(int hora, int minuto) {
int atual = hora * 60 + minuto;
int inicio = 6 * 60 + 30;
int fim = 20 * 60 + 30;
return (atual >= inicio && atual <= fim);
}
String textoAlternado(bool maiusculo, bool wow) {
if (wow) {
return maiusculo ? "WOW!!!!" : "wow!!!!";
} else {
return maiusculo ? "ZZZZZ" : "zzzzz";
}
}
int brilhoRespirando(unsigned long agora, unsigned long periodoMs, int minBrilho, int maxBrilho) {
float fase = (agora % periodoMs) / (float)periodoMs;
float seno = (sin(2.0 * PI * fase - PI / 2.0) + 1.0) / 2.0;
return minBrilho + (int)((maxBrilho - minBrilho) * seno);
}
void atualizarAnimacaoLeds(bool wowAtivo) {
unsigned long agora = millis();
if (wowAtivo) {
int brilho = brilhoRespirando(agora, 1800, 15, 255);
analogWrite(LED_AZUL_1, 0);
analogWrite(LED_AZUL_2, 0);
analogWrite(LED_VERDE_1, brilho);
analogWrite(LED_VERDE_2, brilho);
} else {
int brilho = brilhoRespirando(agora, 3000, 5, 180);
analogWrite(LED_VERDE_1, 0);
analogWrite(LED_VERDE_2, 0);
analogWrite(LED_AZUL_1, brilho);
analogWrite(LED_AZUL_2, brilho);
}
}
String obterNomeRede() {
if (WiFi.status() == WL_CONNECTED) {
String rede = WiFi.SSID();
if (rede.length() == 0) rede = "WIFI";
if (rede.length() > 18) rede = rede.substring(0, 18);
return rede;
}
return "SEM WIFI";
}
String obterIpLocal() {
if (WiFi.status() == WL_CONNECTED) {
return WiFi.localIP().toString();
}
return "0.0.0.0";
}
int obterPercentualWifi() {
if (WiFi.status() != WL_CONNECTED) return 0;
long rssi = WiFi.RSSI();
if (rssi <= -100) return 0;
if (rssi >= -50) return 100;
return map(rssi, -100, -50, 0, 100);
}
uint16_t corWifi(int percentual) {
if (percentual >= 70) return ILI9341_GREEN;
if (percentual >= 40) return ILI9341_YELLOW;
return ILI9341_RED;
}
void desenharBarraWifi(int x, int y, int largura, int altura, int percentual) {
uint16_t cor = corWifi(percentual);
tft.drawRect(x, y, largura, altura, ILI9341_WHITE);
int larguraInterna = largura - 2;
int alturaInterna = altura - 2;
int preenchido = (larguraInterna * percentual) / 100;
tft.fillRect(x + 1, y + 1, larguraInterna, alturaInterna, ILI9341_BLACK);
if (preenchido > 0) {
tft.fillRect(x + 1, y + 1, preenchido, alturaInterna, cor);
}
}
void atualizarTFT(struct tm &timeinfo) {
char horaBuffer[10];
strftime(horaBuffer, sizeof(horaBuffer), "%H:%M:%S", &timeinfo);
String horaTxt = String(horaBuffer);
String dataTxt =
String(timeinfo.tm_mday) + "/" +
String(timeinfo.tm_mon + 1) + "/" +
String(timeinfo.tm_year + 1900);
modoDeepWork = verificarDeepWork(timeinfo.tm_hour, timeinfo.tm_min);
if (horaTxt != ultimaHora) {
tft.fillRect(20, 78, 200, 30, ILI9341_BLACK);
centralizar(horaTxt, 82, 3, ILI9341_WHITE);
ultimaHora = horaTxt;
}
String dataCompleta = diaSemana(timeinfo.tm_wday) + dataTxt;
if (dataCompleta != ultimaData) {
tft.fillRect(20, 145, 200, 45, ILI9341_BLACK);
centralizar(diaSemana(timeinfo.tm_wday), 145, 2, ILI9341_GREEN);
centralizar(dataTxt, 170, 2, ILI9341_WHITE);
ultimaData = dataCompleta;
}
bool wowAtivo = horarioWow(timeinfo.tm_hour, timeinfo.tm_min);
bool maiusculo = ((timeinfo.tm_sec / 10) % 2 == 0);
String linha1 = textoAlternado(maiusculo, wowAtivo);
uint16_t corLinha1 = wowAtivo ? ILI9341_GREEN : ILI9341_BLUE;
String linha2 = modoDeepWork ? "Deep Work" : "Fora do foco";
String linha3 = obterNomeRede();
String linha4 = obterIpLocal();
int wifiPct = obterPercentualWifi();
String linha5 = String(wifiPct) + "%";
String estadoAtual =
linha1 + "|" + linha2 + "|" + linha3 + "|" + linha4 + "|" + linha5 + "|" +
String(timeinfo.tm_sec / 10);
if (estadoAtual != ultimoStatus) {
tft.fillRect(20, 212, 200, 100, ILI9341_BLACK);
centralizar(linha1, 214, 2, corLinha1);
centralizar(linha2, 234, 1, ILI9341_CYAN);
centralizar(linha3, 252, 1, ILI9341_YELLOW);
centralizar(linha4, 270, 1, ILI9341_WHITE);
desenharBarraWifi(32, 290, 130, 12, wifiPct);
tft.setTextSize(1);
tft.setTextColor(corWifi(wifiPct));
tft.setCursor(172, 292);
tft.print(linha5);
ultimoStatus = estadoAtual;
}
}
void atualizar7Seg(struct tm &timeinfo) {
int valor = (timeinfo.tm_hour * 100) + timeinfo.tm_min;
sevseg.setNumber(valor, 2); // ex.: 16.57
}
void setup7Seg() {
byte numDigits = 4;
bool resistorsOnSegments = true;
byte hardwareConfig = COMMON_CATHODE;
bool updateWithDelays = false;
bool leadingZeros = true;
bool disableDecPoint = false;
sevseg.begin(
hardwareConfig,
numDigits,
digitPins,
segmentPins,
resistorsOnSegments,
updateWithDelays,
leadingZeros,
disableDecPoint
);
sevseg.setBrightness(90);
}
void setupLeds() {
pinMode(LED_AZUL_1, OUTPUT);
pinMode(LED_AZUL_2, OUTPUT);
pinMode(LED_VERDE_1, OUTPUT);
pinMode(LED_VERDE_2, OUTPUT);
analogWrite(LED_AZUL_1, 0);
analogWrite(LED_AZUL_2, 0);
analogWrite(LED_VERDE_1, 0);
analogWrite(LED_VERDE_2, 0);
}
void setup() {
setupLeds();
setup7Seg();
tft.begin();
tft.setRotation(0);
telaBase();
conectarWiFi();
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
delay(1000);
telaBase();
}
void loop() {
sevseg.refreshDisplay();
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
return;
}
bool wowAtivo = horarioWow(timeinfo.tm_hour, timeinfo.tm_min);
atualizarTFT(timeinfo);
atualizar7Seg(timeinfo);
atualizarAnimacaoLeds(wowAtivo);
unsigned long inicio = millis();
while (millis() - inicio < 20) {
sevseg.refreshDisplay();
atualizarAnimacaoLeds(wowAtivo);
}
}Board not found
board-esp8266
board-esp8266