#include <ESP32Servo.h>
#include <WiFi.h>
#include <PubSubClient.h>
// Configurações Wifi e MQTT
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* mqttServer = "broker.hivemq.com";
const int mqttPort = 1883;
WiFiClient espClient;
PubSubClient client(espClient);
// Tópicos MQTT
const char* topicTorreta = "sihs/torivus/2/torreta";
//const char* topicEvent = "sihs/torivus/1/event";
const char* topicMovement = "sihs/torivus/2/pir";
const char* topicSound = "sihs/torivus/2/sound";
// Pinos
const int pinServo = 4; // Servo da torreta
const int pinTrigger = 17;
const int pinPir = 16; // Sensor PIR (movimento)
const int pinBuzzer = 25; // Buzzer
const int pinSound = 32; // Sensor de som
// Configurações do Servo
Servo torreta;
int posAtual = 0; // Posição atual do servo
int posAlvo = 0; // Posição alvo do servo
int vel = 10;
bool torretaAtiva = true;
// Configurações dos sensores
int soundLevel = 0; // Dados lidos pelo sensor de som
int pirState = LOW; // Estado do PIR
int soundState = LOW; // Estado do som
const int soundThreshold = 70; // Limiar para som anormal
bool alarmeAtivo = true;
bool buzzerAtivo = true;
bool sensorSomAtivo = true;
bool sensorPirAtivo = true;
// Controle de tempo
unsigned long lastReconnect = 0;
const unsigned long reconnectInterval = 5000;
unsigned long lastPirCheck = 0;
unsigned long lastSoundCheck = 0;
unsigned long lastBuzzerToggle = 0;
unsigned long lastServoMove = 0;
unsigned long lastPrint = 0;
unsigned long lastShootTime = 0;
const unsigned long checkInterval = 1000; // Intervalo de checagem (2s)
const unsigned long buzzerInterval = 1000; // Intervalo do alarme sonoro (500ms)
const unsigned long servoInterval = 100; // Intervalo entre movimentos do servo (50ms)
const unsigned long serialPrintInterval = 1000; // Intervalo entre prints no Serial (1s)
const unsigned long shootInterval = 2000;
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived: ");
Serial.println(topic);
String msg = "";
for (int i = 0; i < length; i++) {
msg += ((char)payload[i]);
}
//Verifica conteudo
Serial.print("Comando: ");
Serial.println(msg);
if (String(topic) == topicTorreta) {
if (msg == "LIGAR_TORRETA") {
torretaAtiva = true;
} else if (msg == "DESLIGAR_TORRETA") {
torretaAtiva = false;
torreta.write(0);
} else if (msg == "LIGAR_ALARME") {
buzzerAtivo = true;
alarmeAtivo = true; // Certifica que o alarme fica ativo
} else if (msg == "DESLIGAR_ALARME") {
buzzerAtivo = false;
alarmeAtivo = false; // Desativa também o alarme
ledcWrite(pinBuzzer, 0); // Certifica que o buzzer para
} else if (msg == "LIGAR_SENSOR_SOM") {
sensorSomAtivo = true;
} else if (msg == "DESLIGAR_SENSOR_SOM") {
sensorSomAtivo = false;
} else if (msg == "LIGAR_SENSOR_MOV") {
sensorPirAtivo = true;
} else if (msg == "DESLIGAR_SENSOR_MOV") {
sensorPirAtivo = false;
}
}
}
void setup() {
Serial.begin(115200);
client.setServer(mqttServer, mqttPort);
client.setCallback(callback);
ledcAttachChannel(pinBuzzer, 1000, 8, 0);
torreta.attach(pinServo);
// Inicializa WiFi
reconnect();
pinMode(pinPir, INPUT);
pinMode(pinSound, INPUT);
pinMode(pinTrigger, OUTPUT);
torreta.write(posAtual); // Inicia a torreta na posição inicial
// Configura o buzzer
// if (!ledcAttachChannel(pinBuzzer, 1000, 8, 0)) { // Frequência: 1kHz, Resolução: 8 bits
// Serial.println("Erro ao configurar buzzer");
// }
Serial.println("Sistema Iniciado");
}
void reconnect() {
//se já está conectado a rede WI-FI, nada é feito.
//Caso contrário, são efetuadas tentativas de conexão
if (WiFi.status() != WL_CONNECTED) {
Serial.print("Tentando conexão Wifi...");
WiFi.begin(ssid, password); // Conecta na rede WI-FI
}
if (millis() - lastReconnect > reconnectInterval) {
lastReconnect = millis();
while (WiFi.status() != WL_CONNECTED)
{
delay(1000);
Serial.print(".");
}
Serial.print("Wifi conectado!");
delay(2000);
// Loop ate conectar mqtt
while (!client.connected()) {
if (WiFi.status() != WL_CONNECTED) {
break;
}
Serial.print("Tentando conexao mqtt...");
if (client.connect("espTorreta2")) {
Serial.println("Conectado ao MQTT.");
//Subscrevendo em um topico
client.subscribe(topicTorreta);
} else {
Serial.print("Falha, rc=");
Serial.print(client.state());
Serial.println(" Tentando novamente em 5s.");
delay(5000);
}
}
}
}
void loop() {
//Conecta MQTT
if (!client.connected()) {
Serial.println("Reconectando ao MQTT...");
reconnect(); //Caso caia a conexao
}
client.loop(); //Deixa MQTT no loop
unsigned long currentMillis = millis();
// Checa o sensor PIR
if (sensorPirAtivo && currentMillis - lastPirCheck >= checkInterval) {
lastPirCheck = currentMillis;
pirState = digitalRead(pinPir);
client.publish(topicMovement, pirState == HIGH ? "1" : "0");
}
// Checa o sensor de som
if (sensorSomAtivo && currentMillis - lastSoundCheck >= checkInterval) {
lastSoundCheck = currentMillis;
soundLevel = analogRead(pinSound);
int soundLevelDb = map(soundLevel, 0, 4095, 30, 120);
soundState = (soundLevelDb > soundThreshold);
char soundMessage[50];
sprintf(soundMessage, "%d", soundLevelDb);
client.publish(topicSound, soundMessage);
}
// Atualiza o estado do alarme com base nos dados dos sensores
if (pirState == HIGH || soundState == HIGH) {
alarmeAtivo = true;
posAlvo = 90; // Torreta vai para posição de disparo
} else {
alarmeAtivo = false;
posAlvo = 0; // Torreta retorna à posição inicial
}
/* Logica para diferenciar eventos e notificar
if (pirState == HIGH && soundState == HIGH) {
alarmeAtivo = true;
posAlvo = 90;
client.publish(topicEvent, "ALERTA CRÍTICO: Movimento e Som Anormal Detectados!");
} else if (pirState == HIGH) {
client.publish(topicEvent, "Movimento Detectado!");
} else if (soundState == HIGH) {
client.publish(topicEvent, "Som Anormal Detectado!");
} else {
alarmeAtivo = false;
posAlvo = 0; // Torreta retorna à posição inicial
} */
// Gerencia o alarme sonoro, movimentação da torreta e disparo
gerenciarBuzzer(currentMillis);
if (torretaAtiva) {
moverTorreta(currentMillis);
if (alarmeAtivo && posAtual == posAlvo) {
dispararTorreta(currentMillis);
}
}
// Imprime no serial a cada 1 segundo
if (currentMillis - lastPrint >= serialPrintInterval) {
lastPrint = currentMillis;
Serial.println("------- Estado Atual -------");
Serial.print("Movimento detectado (PIR): ");
Serial.println(pirState == HIGH ? "Sim" : "Não");
Serial.print("Som detectado: ");
Serial.println(soundState == HIGH ? "Sim" : "Não");
Serial.print("Nível de som: ");
Serial.println(soundLevel);
Serial.print("Posição da torreta: ");
Serial.println(posAtual);
Serial.print("Alarme ativo: ");
Serial.println(alarmeAtivo ? "Sim" : "Não");
Serial.println("----------------------------");
}
}
void verificarSensores() {
int pirState = digitalRead(pinPir);
int soundLevel = analogRead(pinSound);
if (pirState == HIGH || soundLevel > soundThreshold) {
alarmeAtivo = true;
} else {
alarmeAtivo = false;
}
}
void conectarWiFi() {
if (WiFi.status() != WL_CONNECTED) {
WiFi.begin(ssid, password);
}
// Aguarda a conexão sem bloquear o código
unsigned long startMillis = millis();
while (WiFi.status() != WL_CONNECTED) {
if (millis() - startMillis >= 10000) { // Timeout de 10 segundos
Serial.println("Falha ao conectar no Wi-Fi!");
return;
}
delay(1000); // Tenta a conexão a cada segundo
Serial.print(".");
}
Serial.println("\nConectado ao Wifi!");
}
// Função para gerenciar o som intermitente do buzzer
void gerenciarBuzzer(unsigned long currentMillis) {
static bool buzzerLigado = false;
if (alarmeAtivo && buzzerAtivo) {
if (currentMillis - lastBuzzerToggle >= buzzerInterval) {
lastBuzzerToggle = currentMillis;
buzzerLigado = !buzzerLigado;
ledcWrite(pinBuzzer, buzzerLigado ? 128 : 0); // Liga ou desliga o buzzer
}
} else {
ledcWrite(pinBuzzer, 0); // Silêncio absoluto se alarme não está ativo
}
}
// Função para mover a torreta suavemente
void moverTorreta(unsigned long currentMillis) {
if (currentMillis - lastServoMove >= servoInterval) {
lastServoMove = currentMillis;
// Movimento mais suave e preciso
if (posAtual < posAlvo) {
posAtual += vel;
} else if (posAtual > posAlvo) {
posAtual -= vel;
}
torreta.write(posAtual); // Atualiza a posição do servo
}
}
// Função para gerenciar o disparo da torreta
void dispararTorreta(unsigned long currentMillis) {
if (currentMillis - lastShootTime >= shootInterval) {
lastShootTime = currentMillis;
Serial.println("Disparo realizado!");
digitalWrite(pinTrigger, HIGH);
delay(1000); // Simula disparo curto
digitalWrite(pinTrigger, LOW);
}
}