#include <WiFi.h>
#include <PubSubClient.h>
#include <ESP32Servo.h> // Biblioteca de servos para ESP32
// Credenciais Wi-Fi
const String ssidName = "Wokwi-GUEST";
// Configurações do MQTT Broker
const char* mqtt_server = "broker.emqx.io";
const int mqtt_port = 1883;
const char* mqtt_user = "";
const char* mqtt_password = "";
const char* mqtt_clientId = "MIOT-Esp32";
//input pins
const int motionSensorPin = 35;
const int buttonPin = 18;
//output pins
const int ledPin = 2;
const int buzzerPin = 4;
const int servoPin = 33;
typedef struct{
bool isConnectedToTheNetwork = false;
byte numSsid;
int findSsidIndex(String targetSsid) {
// Obtém o número total de redes salvas
int numNetworks = WiFi.scanNetworks();
// Itera por todas as redes salvas
for (int i = 0; i < numNetworks; i++) {
String currentSsid = WiFi.SSID(i);
if (currentSsid.equals(targetSsid)) {
return i;
}
}
// Se a rede não for encontrada, retorna -1
return -1;
}
//Conecta a Rede Por Meio Do Indice Fornecido Pelo metodo findLocalNetworks
bool connectToTheNetworkBySSIDIndex(int ssidIndex, String password = "") {
String ssid = WiFi.SSID(ssidIndex);
if (WiFi.encryptionType(ssidIndex) == WIFI_AUTH_OPEN) {
WiFi.begin(ssid);
} else {
WiFi.begin(ssid, password);
}
Serial.println("Conectando...");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nSucesso");
return true;
}
bool connectToTheNetworkBySSIDName(String ssid, String password = ""){
int ssidIndex = findSsidIndex(ssid);
if(ssidIndex < 0) return false;
connectToTheNetworkBySSIDIndex(ssidIndex, password);
return true;
}
//Procura Pelas redes Identificadas no Local
void findLocalNetworks() {
WiFi.disconnect(); // limpa conexões anteriores
isConnectedToTheNetwork = false;
numSsid = WiFi.scanNetworks();
// print the list of networks seen:
Serial.print("Lista de SSID:");
Serial.println(numSsid);
// print the network number and name for each network found:
for (int thisNet = 0; thisNet < numSsid; thisNet++) {
Serial.print(thisNet);
Serial.println(") Rede: " + String(WiFi.SSID(thisNet)) + " RSSI: " + String(WiFi.RSSI(thisNet)) );
}
}
} Net;
Net network;
WiFiClient espClient;
PubSubClient client(espClient);
bool lastMsg = false;
bool buttonState = false;
int direction = 1;
float motorSpeed = 0.1;
float lastAngle = 0;
Servo servo;
typedef struct{
const String topic;
void (*method)(String msg); // Ponteiro para uma função que não retorna nada e não recebe parâmetros
} Topic;
void motorTopic (String msg) {
msg.trim();
lastMsg = msg.equalsIgnoreCase(String("ON"));
}
void motorSpeedTopic(String msg){
motorSpeed = msg.toFloat();
}
Topic topics[] = {
{"miot/motor", motorTopic},
{"miot/motor/speed", motorSpeedTopic},
};
const int numOfTopics = sizeof(topics) / sizeof(Topic);
//executa os topicos e retorna se foi executado ou nao
bool executeTopicMethod(const String topic, int numOfTopics, Topic topics[], String msg="") {
// Percorre o array de comandos
for (int i = 0; i < numOfTopics; i++) {
// Compara a string recebida com a string na struct
if (topic.equals((topics[i]).topic)) {
// Se a string for igual, chama a função através do ponteiro
topics[i].method(msg);
return true; // retorna se o metodo do topico foi executado
}
}
return false;
}
void reconnect() {
while (client.connected() != 1) {
if (client.connect(mqtt_clientId)) {
Serial.print("MQTT state: ");
Serial.println(client.state());
for(int i = 0; i < numOfTopics; i++) {
client.subscribe(topics[i].topic.c_str());
}
} else {
delay(1000);
}
}
}
volatile unsigned long lastDebounceTime = 0;
const unsigned long DEBOUNCE_DELAY = 30;
int count = 0;
void IRAM_ATTR onPressed() {
// Funcao chamada pela interrupcao
unsigned long currentTime = millis();
// Apenas executa se o tempo de debounce ja passou
if (digitalRead(buttonPin) == LOW &&
currentTime - lastDebounceTime > DEBOUNCE_DELAY
) {
if(count % 2 == 0) {
// Altera o estado do botao
buttonState = !buttonState;
}
count++;
// Atualiza o tempo do ultimo acionamento
lastDebounceTime = currentTime;
}
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
pinMode(motionSensorPin, INPUT);
pinMode(buttonPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
pinMode(buzzerPin, OUTPUT);
servo.attach(servoPin);
attachInterrupt(digitalPinToInterrupt(buttonPin), onPressed, FALLING);
network.connectToTheNetworkBySSIDName(ssidName);
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
reconnect();
definineLedState(false);
Serial.println("Setup Finalizado");
}
void rotateIndefinitelyMotor(const float speed = 1) {
if (lastMsg) {
servo.write(lastAngle);
lastAngle += direction * speed;
if(lastAngle >= 180 || lastAngle <= 0) {
direction = -direction;
}
}
}
void definineLedState(bool state) {
if(state == true){
digitalWrite(ledPin, HIGH);
client.publish("miot/led", "ON"); // Exemplo de publicação
return;
}
digitalWrite(ledPin, LOW);
client.publish("miot/led", "OFF"); // Exemplo de publicação
}
unsigned long long int lastMillis = 0;
void loop() {
if (client.connected() != 1) {
Serial.println("Nao Conectado");
Serial.println(client.state());
reconnect();
}
client.loop();
unsigned long long int milis = millis();
if(buttonState == true) {
definineLedState(false);
noTone(buzzerPin);
return;
}
int motionSensorState = LOW;
if(motionSensorState = digitalRead(motionSensorPin)){
definineLedState(true);
tone(buzzerPin, 1000);
return;
}
if(milis -lastMillis >= 33) {
if (buttonState == false) {
//Serial.println("teste");
}
rotateIndefinitelyMotor(motorSpeed);
definineLedState(false);
noTone(buzzerPin);
lastMillis = millis();
}
}
void callback(char* topic, byte* message, unsigned int length) {
String msg;
for (int i = 0; i < length; i++) {
msg += (char)message[i];
}
msg.trim();
Serial.println("MSG: " + msg);
Serial.println("TOPICO: " + String(topic));
executeTopicMethod(String(topic), numOfTopics, topics, msg);
}