//Autor: Fábio Henrique Cabrini (Rev5: Lâmpada Inteligente + Despertador)
//Resumo: LED RGB PWM com modos Auto/Foco/Relax + Despertador com horário internet e sensor de movimento
#include <WiFi.h>
#include <PubSubClient.h>
#include <time.h>
// === CONFIGURAÇÕES GERAIS ===
const char* default_SSID = "Wokwi-GUEST";
const char* default_PASSWORD = "";
const char* default_BROKER_MQTT = "100.31.71.212";
const int default_BROKER_PORT = 1883;
const char* default_TOPICO_SUBSCRIBE = "/TEF/lamp009/cmd";
const char* default_TOPICO_PUBLISH_1 = "/TEF/lamp009/attrs";
const char* default_TOPICO_PUBLISH_2 = "/TEF/lamp009/attrs/l";
const char* default_ID_MQTT = "fiware_009";
// === CONFIGURAÇÕES DE HORÁRIO ===
const char* NTPSERVER = "pool.ntp.br";
const int GMT_OFFSET = -10800; // UTC-3 Brasil
const int DAYLIGHT_OFFSET = 0;
// === PINOS ===
const int LED_R = 25, LED_G = 26, LED_B = 27;
const int LDR_PIN = 34;
const int SENSOR_MOVIMENTO = 32;
const int BUZZER = 23;
// === ENUM MODOS LÂMPADA ===
enum ModoLampada {
AUTOMATICO,
FOCO,
RELAXAR,
OFF
};
ModoLampada modoAtual = OFF;
// === VARIÁVEIS DO DESPERTADOR ===
int horaAlarme = 7;
int minutoAlarme = 0;
bool alarmeAtivo = false;
bool alarmeTocando = false;
unsigned long inicioAlarme = 0;
const unsigned long DURACAO_ALARME = 60000; // 1 minuto
unsigned long ultimoMovimento = 0;
// === VARIÁVEIS DE TEMPO ===
int horaAtual = 0;
int minutoAtual = 0;
int segundoAtual = 0;
// === VALORES FIXOS DOS MODOS ===
const int FOCO_R = 255, FOCO_G = 255, FOCO_B = 255;
const int RELAX_R = 255, RELAX_G = 120, RELAX_B = 40;
WiFiClient espClient;
PubSubClient MQTT(espClient);
char* SSID = const_cast<char*>(default_SSID);
char* PASSWORD = const_cast<char*>(default_PASSWORD);
char* BROKER_MQTT = const_cast<char*>(default_BROKER_MQTT);
int BROKER_PORT = default_BROKER_PORT;
char* TOPICO_SUBSCRIBE = const_cast<char*>(default_TOPICO_SUBSCRIBE);
char* TOPICO_PUBLISH_1 = const_cast<char*>(default_TOPICO_PUBLISH_1);
char* TOPICO_PUBLISH_2 = const_cast<char*>(default_TOPICO_PUBLISH_2);
char* ID_MQTT = const_cast<char*>(default_ID_MQTT);
// === VARIÁVEIS PARA ATUALIZAÇÃO PERIÓDICA ===
unsigned long ultimaAtualizacaoHorario = 0;
unsigned long ultimaAtualizacaoLuminosidade = 0;
void setup() {
Serial.begin(115200);
alarmeAtivo = true;
horaAlarme = 19; // Coloque um minuto a frente do atual
minutoAlarme = 22;
// Configuração dos pinos
pinMode(LED_R, OUTPUT);
pinMode(LED_G, OUTPUT);
pinMode(LED_B, OUTPUT);
pinMode(SENSOR_MOVIMENTO, INPUT);
pinMode(BUZZER, OUTPUT);
// Inicializações
InitOutput();
initWiFi();
initMQTT();
initTime();
// Garante que inicia OFF
modoAtual = OFF;
ligarLampada(0, 0, 0);
MQTT.publish(TOPICO_PUBLISH_1, "m|off");
MQTT.publish(TOPICO_PUBLISH_1, "s|off");
// Teste do buzzer
tomBuzzer(2000, 200);
delay(200);
tomBuzzer(2000, 200);
Serial.println("✅ Lâmpada 009 Inteligente + Despertador Inicializado!");
Serial.println("Comandos Lâmpada: lamp009@[on/off/auto/foco/relax|]");
Serial.println("Comandos Despertador: set|HH:MM, alarme|[on/off], stop|alarme");
}
void loop() {
VerificaConexoesWiFIEMQTT();
// Atualiza horário da internet
atualizarHorario();
// === ATUALIZAÇÕES PERIÓDICAS A CADA 3 SEGUNDOS ===
if (millis() - ultimaAtualizacaoHorario >= 3000) {
publicarHorarioAtual();
ultimaAtualizacaoHorario = millis();
}
if (millis() - ultimaAtualizacaoLuminosidade >= 3000) {
int lum = lerLuminosidade();
MQTT.publish(TOPICO_PUBLISH_2, String(lum).c_str());
Serial.print("📊 Luminosidade atualizada: ");
Serial.println(lum);
ultimaAtualizacaoLuminosidade = millis();
}
// === CONTROLE DA LÂMPADA ===
// Se o alarme NÃO está tocando, controla a lâmpada normalmente
if (!alarmeTocando) {
switch (modoAtual) {
case AUTOMATICO:
modoLDR();
break;
case FOCO:
ligarLampada(FOCO_R, FOCO_G, FOCO_B);
break;
case RELAXAR:
ligarLampada(RELAX_R, RELAX_G, RELAX_B);
break;
case OFF:
ligarLampada(0, 0, 0);
break;
}
} else {
// Durante o alarme, a lâmpada faz efeito de amanhecer
efeitoAmanhecerAlarme();
}
// === CONTROLE DO DESPERTADOR ===
verificarAlarme();
gerenciarAlarme();
// === MQTT ===
EnviaEstadoMQTT();
MQTT.loop();
delay(100);
}
// === FUNÇÕES DA LÂMPADA ===
void ligarLampada(int r, int g, int b) {
analogWrite(LED_R, r);
analogWrite(LED_G, g);
analogWrite(LED_B, b);
}
void modoLDR() {
static unsigned long ultimoCheck = 0;
if (millis() - ultimoCheck > 1500) {
int ldr = lerLuminosidade();
if (modoAtual == AUTOMATICO) {
if (ldr < 25) ligarLampada(255, 255, 255);
else if (ldr < 60) ligarLampada(200, 150, 80);
else ligarLampada(50, 30, 10);
}
ultimoCheck = millis();
}
}
int lerLuminosidade() {
return map(analogRead(LDR_PIN), 0, 4095, 0, 100);
}
void InitOutput() {
Serial.println("🌈 Inicializando RGB - Lâmpada 009...");
for (int i = 0; i <= 10; i++) {
bool toggle = (i % 2 == 0);
ligarLampada(toggle*255, toggle*255, toggle*255);
delay(200);
}
ligarLampada(0, 0, 0);
Serial.println("✅ Inicialização concluída");
}
// === FUNÇÕES DO DESPERTADOR ===
void initTime() {
configTime(GMT_OFFSET, DAYLIGHT_OFFSET, NTPSERVER);
Serial.print("⏰ Sincronizando horário...");
struct tm timeinfo;
while (!getLocalTime(&timeinfo)) {
Serial.print(".");
delay(1000);
}
Serial.println(" OK!");
char buffer[80];
strftime(buffer, 80, "%d/%m/%Y %H:%M:%S", &timeinfo);
Serial.print("📅 Horário atual: ");
Serial.println(buffer);
}
void atualizarHorario() {
struct tm timeinfo;
if (getLocalTime(&timeinfo)) {
horaAtual = timeinfo.tm_hour;
minutoAtual = timeinfo.tm_min;
segundoAtual = timeinfo.tm_sec;
}
}
void publicarHorarioAtual() {
String horarioMsg = "hora|" + String(horaAtual) + ":" + String(minutoAtual) + ":" + String(segundoAtual);
MQTT.publish(TOPICO_PUBLISH_1, horarioMsg.c_str());
Serial.print("🕐 Horário publicado: ");
Serial.print(horaAtual);
Serial.print(":");
Serial.print(minutoAtual);
Serial.print(":");
Serial.println(segundoAtual);
}
void verificarAlarme() {
// Se o alarme está ativo e ainda não está tocando
if (alarmeAtivo && !alarmeTocando) {
// Verifica se a hora e o minuto coincidem com o alarme
if (horaAtual == horaAlarme && minutoAtual == minutoAlarme) {
// Dispara apenas nos primeiros segundos do minuto para evitar repetições
if (segundoAtual < 5) {
Serial.println("⏰ HORA DE ACORDAR! Condição atingida.");
dispararAlarme();
}
}
}
}
void dispararAlarme() {
alarmeTocando = true;
inicioAlarme = millis();
ultimoMovimento = millis();
Serial.println("🚨 ALARME DISPARADO! 🚨");
MQTT.publish(TOPICO_PUBLISH_1, "alarme|disparado");
}
void gerenciarAlarme() {
if (!alarmeTocando) return;
// Verifica movimento
bool movimento = digitalRead(SENSOR_MOVIMENTO);
if (movimento) {
ultimoMovimento = millis();
Serial.println("👤 Movimento detectado!");
}
// Verifica se passou 1 minuto sem movimento
if (millis() - ultimoMovimento > DURACAO_ALARME) {
Serial.println("⏰ Sem movimento! Reiniciando alarme...");
reiniciarAlarme();
}
// Verifica se o alarme já tocou por 1 minuto
if (millis() - inicioAlarme > DURACAO_ALARME) {
Serial.println("✅ Alarme concluído");
pararAlarme();
}
// Toca o buzzer
tocarAlarme();
}
void reiniciarAlarme() {
inicioAlarme = millis();
ultimoMovimento = millis();
Serial.println("🔄 Alarme reiniciado!");
MQTT.publish(TOPICO_PUBLISH_1, "alarme|reiniciado");
}
void pararAlarme() {
alarmeTocando = false;
noTone(BUZZER);
Serial.println("🔇 Alarme parado!");
MQTT.publish(TOPICO_PUBLISH_1, "alarme|parado");
// Restaura o modo anterior da lâmpada
ligarLampada(0, 0, 0);
}
void tocarAlarme() {
static unsigned long ultimoTom = 0;
static int frequencia = 2000;
static bool subindo = true;
if (millis() - ultimoTom > 300) {
if (subindo) {
frequencia += 100;
if (frequencia >= 3000) subindo = false;
} else {
frequencia -= 100;
if (frequencia <= 1500) subindo = true;
}
tone(BUZZER, frequencia, 200);
ultimoTom = millis();
}
}
void tomBuzzer(int frequencia, int duracao) {
tone(BUZZER, frequencia, duracao);
delay(duracao);
noTone(BUZZER);
}
void efeitoAmanhecerAlarme() {
unsigned long progresso = millis() - inicioAlarme;
int intensidade = map(progresso, 0, DURACAO_ALARME, 0, 255);
if (intensidade > 255) intensidade = 255;
// Luz âmbar para amanhecer
ligarLampada(255, intensidade * 0.8, intensidade * 0.4);
}
// === FUNÇÕES MQTT ===
// === FUNÇÕES MQTT ===
void mqtt_callback(char* topic, byte* payload, unsigned int length) {
String msg;
for (int i = 0; i < length; i++) msg += (char)payload[i];
Serial.print("📨 Comando recebido: ");
Serial.println(msg);
// ===== TRATAMENTO PARA COMANDOS JSON =====
// Verifica se é um JSON contendo "alarme"
if (msg.indexOf("\"alarme\"") > 0 && msg.indexOf("\"value\"") > 0) {
if (msg.indexOf("\"on\"") > 0) {
alarmeAtivo = true;
Serial.println("✅ Alarme ATIVADO via JSON");
MQTT.publish(TOPICO_PUBLISH_1, "alarme|ativado");
MQTT.publish(TOPICO_PUBLISH_1, "alarme|confirmado|on");
return;
}
else if (msg.indexOf("\"off\"") > 0) {
alarmeAtivo = false;
alarmeTocando = false;
noTone(BUZZER);
Serial.println("❌ Alarme DESATIVADO via JSON");
MQTT.publish(TOPICO_PUBLISH_1, "alarme|desativado");
MQTT.publish(TOPICO_PUBLISH_1, "alarme|confirmado|off");
return;
}
}
// ===== TRATAMENTO PARA COMANDOS JSON DE SET HORÁRIO =====
if (msg.indexOf("\"set\"") > 0 || msg.indexOf("\"horario\"") > 0) {
// Procura por padrão HH:MM no JSON
int pos1 = msg.indexOf("\"");
int pos2 = msg.lastIndexOf("\"");
if (pos1 > 0 && pos2 > pos1) {
String horario = msg.substring(pos1 + 1, pos2);
int separador = horario.indexOf(':');
if (separador > 0) {
int h = horario.substring(0, separador).toInt();
int m = horario.substring(separador + 1).toInt();
if (h >= 0 && h <= 23 && m >= 0 && m <= 59) {
horaAlarme = h;
minutoAlarme = m;
Serial.printf("⏰ Alarme definido para %02d:%02d via JSON\n", horaAlarme, minutoAlarme);
MQTT.publish(TOPICO_PUBLISH_1, ("alarme|set|" + String(horaAlarme) + ":" + String(minutoAlarme)).c_str());
MQTT.publish(TOPICO_PUBLISH_1, "alarme|confirmado");
return;
}
}
}
}
// ===== COMANDOS DA LÂMPADA (formato original) =====
if (msg == "lamp009@on|") {
modoAtual = AUTOMATICO;
atualizarHorario();
int lum = lerLuminosidade();
MQTT.publish(TOPICO_PUBLISH_2, String(lum).c_str());
String horarioMsg = "hora|" + String(horaAtual) + ":" + String(minutoAtual) + ":" + String(segundoAtual);
MQTT.publish(TOPICO_PUBLISH_1, horarioMsg.c_str());
MQTT.publish(TOPICO_PUBLISH_1, "s|on");
MQTT.publish(TOPICO_PUBLISH_1, "m|auto");
Serial.println("✅ Lâmpada 009 Ligada - Modo Automático");
Serial.print("📅 Horário atualizado: ");
Serial.print(horaAtual);
Serial.print(":");
Serial.print(minutoAtual);
Serial.print(":");
Serial.println(segundoAtual);
Serial.print("💡 Luminosidade: ");
Serial.println(lum);
return;
}
if (msg == "lamp009@off|") {
modoAtual = OFF;
MQTT.publish(TOPICO_PUBLISH_1, "s|off");
MQTT.publish(TOPICO_PUBLISH_1, "m|off");
Serial.println("🔴 Lâmpada 006 Desligada");
return;
}
if (modoAtual != OFF) {
if (msg == "lamp009@auto|") {
modoAtual = AUTOMATICO;
MQTT.publish(TOPICO_PUBLISH_1, "s|on");
MQTT.publish(TOPICO_PUBLISH_1, "m|auto");
Serial.println("✅ Modo Automático");
}
else if (msg == "lamp009@foco|") {
modoAtual = FOCO;
MQTT.publish(TOPICO_PUBLISH_1, "s|on");
MQTT.publish(TOPICO_PUBLISH_1, "m|foco");
ligarLampada(FOCO_R, FOCO_G, FOCO_B);
Serial.println("💡 Modo FOCO - Branco Fixo");
}
else if (msg == "lamp009@relax|") {
modoAtual = RELAXAR;
MQTT.publish(TOPICO_PUBLISH_1, "s|on");
MQTT.publish(TOPICO_PUBLISH_1, "m|relax");
ligarLampada(RELAX_R, RELAX_G, RELAX_B);
Serial.println("🕯️ Modo RELAXAR - Amarelo Fixo");
}
}
// ===== COMANDOS DO DESPERTADOR (formato original) =====
if (msg.startsWith("lamp009@set|")) {
String horario = msg.substring(12);
int separador = horario.indexOf(':');
if (separador > 0) {
horaAlarme = horario.substring(0, separador).toInt();
minutoAlarme = horario.substring(separador + 1).toInt();
if (horaAlarme >= 0 && horaAlarme <= 23 && minutoAlarme >= 0 && minutoAlarme <= 59) {
Serial.printf("⏰ Alarme definido para %02d:%02d\n", horaAlarme, minutoAlarme);
MQTT.publish(TOPICO_PUBLISH_1, ("alarme|set|" + String(horaAlarme) + ":" + String(minutoAlarme)).c_str());
MQTT.publish(TOPICO_PUBLISH_1, "alarme|confirmado");
} else {
Serial.println("❌ Horário inválido!");
MQTT.publish(TOPICO_PUBLISH_1, "erro|horario_invalido");
}
}
}
else if (msg == "lamp009@alarme|on") {
alarmeAtivo = true;
Serial.println("✅ Alarme ATIVADO");
MQTT.publish(TOPICO_PUBLISH_1, "alarme|ativado");
MQTT.publish(TOPICO_PUBLISH_1, "alarme|confirmado|on");
}
else if (msg == "lamp009@alarme|off") {
alarmeAtivo = false;
alarmeTocando = false;
noTone(BUZZER);
Serial.println("❌ Alarme DESATIVADO");
MQTT.publish(TOPICO_PUBLISH_1, "alarme|desativado");
MQTT.publish(TOPICO_PUBLISH_1, "alarme|confirmado|off");
}
else if (msg == "lamp009@stop|alarme") {
if (alarmeTocando) {
pararAlarme();
MQTT.publish(TOPICO_PUBLISH_1, "alarme|parado_remoto");
} else {
MQTT.publish(TOPICO_PUBLISH_1, "alarme|nao_tocando");
}
}
else if (msg == "lamp009@status|") {
String status = "hora=" + String(horaAtual) + ":" + String(minutoAtual) +
",alarme=" + String(alarmeAtivo ? "on" : "off") +
",hora_alarme=" + String(horaAlarme) + ":" + String(minutoAlarme) +
",modo_lampada=" + String(modoAtual);
MQTT.publish(TOPICO_PUBLISH_1, status.c_str());
Serial.println("📊 Status enviado");
}
}
void EnviaEstadoMQTT() {
static unsigned long ultimoStatus = 0;
if (millis() - ultimoStatus > 5000) {
String status;
switch(modoAtual) {
case AUTOMATICO: status = "m|auto"; break;
case FOCO: status = "m|foco"; break;
case RELAXAR: status = "m|relax"; break;
case OFF: status = "m|off"; break;
}
MQTT.publish(TOPICO_PUBLISH_1, status.c_str());
ultimoStatus = millis();
}
}
// === CONEXÕES ===
void initWiFi() {
Serial.print("📶 Conectando WiFi...");
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\n✅ WiFi OK: " + WiFi.localIP().toString());
}
void initMQTT() {
MQTT.setServer(BROKER_MQTT, BROKER_PORT);
MQTT.setCallback(mqtt_callback);
}
void VerificaConexoesWiFIEMQTT() {
if (!MQTT.connected()) {
if (MQTT.connect(ID_MQTT)) {
MQTT.subscribe(TOPICO_SUBSCRIBE);
Serial.println("✅ MQTT Conectado!");
MQTT.publish(TOPICO_PUBLISH_1, "status|online");
MQTT.publish(TOPICO_PUBLISH_1, "s|off");
MQTT.publish(TOPICO_PUBLISH_1, "m|off");
} else {
Serial.print(".");
delay(2000);
}
}
if (WiFi.status() != WL_CONNECTED) initWiFi();
}