#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_MPU6050.h>
#include <time.h>
#include <WiFi.h>
#include <PubSubClient.h> // Importa a Biblioteca PubSubClient
//defines:
//defines de id mqtt e tópicos para publicação e subscribe denominado TEF(Telemetria e Monitoramento de Equipamentos)
#define TOPICO_SUBSCRIBE "/TEF/Hc034/cmd" //tópico MQTT de escuta
#define TOPICO_PUBLISH "/TEF/Hc034/attrs" //tópico MQTT de envio de informações para Broker
#define TOPICO_PUBLISH_2 "/TEF/Hc034/attrs/i" //tópico MQTT de envio de informações para Broker
//IMPORTANTE: recomendamos fortemente alterar os nomes
// desses tópicos. Caso contrário, há grandes
// chances de você controlar e monitorar o ESP32
// de outra pessoa.
#define ID_MQTT "fiware_Hc_034" //id mqtt (para identificação de sessão)
//IMPORTANTE: este deve ser único no broker (ou seja,
// se um client MQTT tentar entrar com o mesmo
// id de outro já conectado ao broker, o broker
// irá fechar a conexão de um deles).
// o valor "n" precisa ser único!
// WIFI
const char* SSID = "FIAP-IBM"; // SSID / nome da rede WI-FI que deseja se conectar
const char* PASSWORD = "Challenge@23!"; // Senha da rede WI-FI que deseja se conectar
// MQTT
const char* BROKER_MQTT = "46.17.108.113"; //URL do broker MQTT que se deseja utilizar
int BROKER_PORT = 1883; // Porta do Broker MQTT
int D4 = 2;
//Variáveis e objetos globais
WiFiClient espClient; // Cria o objeto espClient
PubSubClient MQTT(espClient); // Instancia o Cliente MQTT passando o objeto espClient
char EstadoSaida = '0'; //variável que armazena o estado atual da saída
//Prototypes
void initSerial();
void initWiFi();
void initMQTT();
void reconectWiFi();
void mqtt_callback(char* topic, byte* payload, unsigned int length);
void VerificaConexoesWiFIEMQTT(void);
void InitOutput(void);
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_MPU6050 mpu;
#define PULSE_PER_BEAT 1
#define INTERRUPT_PIN 5
#define SAMPLING_INTERVAL 1000
volatile uint16_t pulse;
uint16_t count;
float heartRate;
float temperatura;
time_t currentTime;
portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
void IRAM_ATTR HeartRateInterrupt() {
portENTER_CRITICAL_ISR(&mux);
pulse++;
portEXIT_CRITICAL_ISR(&mux);
}
void setup() {
Serial.begin(115200);
// Configurar conexão WiFi
WiFi.begin("Wokwi-GUEST", "", 6);
while (WiFi.status() != WL_CONNECTED) {
delay(250);
}
Serial.println("");
Serial.println("WiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// Inicializar o horário com NTP após a conexão WiFi ser estabelecida
configTime(0, 0, "pool.ntp.org");
if (!mpu.begin()) {
Serial.println("Failed to initialize MPU6050!");
while (1);
}
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.setTextColor(WHITE);
display.clearDisplay();
display.setTextSize(2);
display.setCursor(0, 20);
display.display();
pinMode(INTERRUPT_PIN, INPUT);
attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), HeartRateInterrupt, RISING);
while (!Serial);
//inicializações:
InitOutput();
initSerial();
initWiFi();
initMQTT();
delay(5000);
MQTT.publish(TOPICO_PUBLISH, "s|on");
}
//Função: inicializa comunicação serial com baudrate 115200 (para fins de monitorar no terminal serial
// o que está acontecendo.
//Parâmetros: nenhum
//Retorno: nenhum
void initSerial()
{
Serial.begin(115200);
}
//Função: inicializa e conecta-se na rede WI-FI desejada
//Parâmetros: nenhum
//Retorno: nenhum
void initWiFi()
{
delay(10);
Serial.println("------Conexao WI-FI------");
Serial.print("Conectando-se na rede: ");
Serial.println(SSID);
Serial.println("Aguarde");
reconectWiFi();
}
//Função: inicializa parâmetros de conexão MQTT(endereço do
// broker, porta e seta função de callback)
//Parâmetros: nenhum
//Retorno: nenhum
void initMQTT()
{
MQTT.setServer(BROKER_MQTT, BROKER_PORT); //informa qual broker e porta deve ser conectado
MQTT.setCallback(mqtt_callback); //atribui função de callback (função chamada quando qualquer informação de um dos tópicos subescritos chega)
}
//Função: função de callback
// esta função é chamada toda vez que uma informação de
// um dos tópicos subescritos chega)
//Parâmetros: nenhum
//Retorno: nenhum
void mqtt_callback(char* topic, byte* payload, unsigned int length)
{
String msg;
//obtem a string do payload recebido
for(int i = 0; i < length; i++)
{
char c = (char)payload[i];
msg += c;
}
Serial.print("- Mensagem recebida: ");
Serial.println(msg);
//toma ação dependendo da string recebida:
//verifica se deve colocar nivel alto de tensão na saída D0:
//IMPORTANTE: o Led já contido na placa é acionado com lógica invertida (ou seja,
//enviar HIGH para o output faz o Led apagar / enviar LOW faz o Led acender)
if (msg.equals("lamp001@on|"))
{
digitalWrite(D4, HIGH);
EstadoSaida = '1';
}
//verifica se deve colocar nivel alto de tensão na saída D0:
if (msg.equals("lamp001@off|"))
{
digitalWrite(D4, LOW);
EstadoSaida = '0';
}
}
//Função: reconecta-se ao broker MQTT (caso ainda não esteja conectado ou em caso de a conexão cair)
// em caso de sucesso na conexão ou reconexão, o subscribe dos tópicos é refeito.
//Parâmetros: nenhum
//Retorno: nenhum
void reconnectMQTT()
{
while (!MQTT.connected())
{
Serial.print("* Tentando se conectar ao Broker MQTT: ");
Serial.println(BROKER_MQTT);
if (MQTT.connect(ID_MQTT))
{
Serial.println("Conectado com sucesso ao broker MQTT!");
MQTT.subscribe(TOPICO_SUBSCRIBE);
}
else
{
Serial.println("Falha ao reconectar no broker.");
Serial.println("Havera nova tentatica de conexao em 2s");
delay(2000);
}
}
}
//Função: reconecta-se ao WiFi
//Parâmetros: nenhum
//Retorno: nenhum
void reconectWiFi()
{
//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)
return;
WiFi.begin(SSID, PASSWORD); // Conecta na rede WI-FI
while (WiFi.status() != WL_CONNECTED)
{
delay(100);
Serial.print(".");
}
Serial.println();
Serial.print("Conectado com sucesso na rede ");
Serial.print(SSID);
Serial.println("IP obtido: ");
Serial.println(WiFi.localIP());
}
//Função: verifica o estado das conexões WiFI e ao broker MQTT.
// Em caso de desconexão (qualquer uma das duas), a conexão
// é refeita.
//Parâmetros: nenhum
//Retorno: nenhum
void VerificaConexoesWiFIEMQTT(void)
{
if (!MQTT.connected())
reconnectMQTT(); //se não há conexão com o Broker, a conexão é refeita
reconectWiFi(); //se não há conexão com o WiFI, a conexão é refeita
}
//Função: envia ao Broker o estado atual do output
//Parâmetros: nenhum
//Retorno: nenhum
void EnviaEstadoOutputMQTT(void)
{
if (EstadoSaida == '1')
{
MQTT.publish(TOPICO_PUBLISH, "s|on");
}
if (EstadoSaida == '0')
{
MQTT.publish(TOPICO_PUBLISH, "s|off");
}
delay(1000);
}
//Função: inicializa o output em nível lógico baixo
//Parâmetros: nenhum
//Retorno: nenhum
void InitOutput(void)
{
pinMode(D4, OUTPUT);
digitalWrite(D4, HIGH);
boolean toggle = false;
for(int i = 0; i <= 10; i++)
{
toggle = !toggle;
digitalWrite(D4,toggle);
delay(200);
}
}
void loop() {
//garante funcionamento das conexões WiFi e ao broker MQTT
VerificaConexoesWiFIEMQTT();
//envia o status de todos os outputs para o Broker no protocolo esperado
EnviaEstadoOutputMQTT();
display.clearDisplay();
HeartRate();
Temperature();
showTime();
display.display();
delay(500);
}
void HeartRate() {
static unsigned long startTime;
if (millis() - startTime < SAMPLING_INTERVAL) return;
startTime = millis();
portENTER_CRITICAL(&mux);
count = pulse;
pulse = 0;
portEXIT_CRITICAL(&mux);
heartRate = map(count, 0, 220, 0, 220);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.print("BPM: ");
display.print(heartRate, 2);
Serial.println("Heart Rate: " + String(heartRate, 2) + " BPM");
}
char msgBuffer[20]; // garantir espaço suficiente
void Temperature() {
Wire.beginTransmission(0x68);
Wire.write(0x41);
Wire.endTransmission(false);
Wire.requestFrom(0x68, 2);
if (Wire.available() >= 2) {
int16_t tempRaw = Wire.read() << 8 | Wire.read();
temperatura = (float)tempRaw / 340.0 + 36.53;
}
// Formatando a string no buffer
snprintf(msgBuffer, sizeof(msgBuffer), "%.2f", temperatura);
// Publicar no tópico MQTT
MQTT.publish(TOPICO_PUBLISH_2, msgBuffer);
MQTT.loop();
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 20);
display.print("Temp: ");
display.print(temperatura, 1);
Serial.println("Temperatura: " + String(temperatura, 2) + "C");
}
void showTime() {
currentTime = time(nullptr);
struct tm *timeInfo;
timeInfo = localtime(¤tTime);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 40);
display.print(timeInfo->tm_hour);
display.print(":");
display.print(timeInfo->tm_min);
display.print(":");
display.print(timeInfo->tm_sec);
Serial.printf("Time: %02d:%02d:%02d\n", timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec);
}