// Gian Ferrari
// Turma 1 - Embarcados
// Atividade 2
// FUNÇÃO:
// ESP32 #2 - Ponte MQTTX Web (EMQX) <-> Ubidots
#include <WiFi.h>
#include <PubSubClient.h>
// ---- WiFi Wokwi -------------------------------------
const char* WIFI_SSID = "Wokwi-GUEST";
const char* WIFI_PASSWORD = "";
// ---- MQTT (MQTTX WEB / EMQX) -------------------------
const char* EMQX_BROKER = "broker.emqx.io";
const int EMQX_PORT = 1883;
const char* EMQX_CLIENTID = "";
// Tópicos (iguais ao ESP32 #1)
const char* EMQX_SUB_TOPIC = "esp32_Gian_Atividade2"; // ponte assina (telemetria do #1)
const char* EMQX_PUB_TOPIC = "esp32_Gian_Atividade2_Sub"; // ponte publica (comando pro #1)
// ---- MQTT Ubidots ----------------------------------------
const char* UBI_BROKER = "industrial.api.ubidots.com";
const int UBI_PORT = 1883;
const char* UBI_CLIENTID = "";
const char* UBI_TOKEN = "BBUS-Zyu2fNbmEm5y5RoXJJc4Lsdtp5jjLd"; // Token mqtt ubidots
const char* UBI_SUB_TOPIC = "/v1.6/devices/esp32-at2/rele/lv"; // recebe comando relé
const char* UBI_PUB_TOPIC = "/v1.6/devices/esp32-at2"; // publica variáveis
// ---- Variáveis -------------------------- ------------
char msg[255];
float temperatura = 00.0;
float umidade = 00.0;
float lux = 0.0;
bool releOn = false;
// ---- MQTT clients -----------------------------------
WiFiClient espClientEMQX;
WiFiClient espClientUBI;
PubSubClient emqx(espClientEMQX); // EMQX (ESP32 #1)
PubSubClient ubi(espClientUBI); // Ubidots
String emqxClientIdStr;
String ubiClientIdStr;
unsigned long lastMsg = 0;
// ---- Callback EMQX: recebe telemetria do ESP32 #1 ----
// Espera o formato publicado pelo ESP32 #1:
// {"temperatura": 12.34, "umidade": 56.7, "lux": 890.1, "rele": 0}
void emqxCallback(char* topic, byte* payload, unsigned int length) {
char buf[255];
unsigned int n = (length < sizeof(buf) - 1) ? length : (sizeof(buf) - 1);
memcpy(buf, payload, n);
buf[n] = '\0';
int releTmp = 0;
// "dadosValidos" = quantidade de campos extraídos pelo sscanf (0..4)
int dadosValidos = sscanf(
buf,
"{\"temperatura\": %f, \"umidade\": %f, \"lux\": %f, \"rele\": %d}",
&temperatura,
&umidade,
&lux,
&releTmp
);
if (dadosValidos >= 3) {
if (dadosValidos == 4) {
releOn = (releTmp >= 1);
}
Serial.print("[EMQX] Recebido: ");
Serial.println(buf);
} else {
Serial.print("[EMQX] Recebido [inválido]: ");
Serial.println(buf);
}
}
// ---- Callback Ubidots: recebe comando relé e repassa ao EMQX ----
// Ubidots /lv geralmente envia "0" ou "1"
void ubiCallback(char* topic, byte* payload, unsigned int length) {
char buf[32];
unsigned int n = (length < sizeof(buf) - 1) ? length : (sizeof(buf) - 1);
memcpy(buf, payload, n);
buf[n] = '\0';
releOn = (atof(buf) >= 1.0);
// Repassa para o ESP32 #1 no formato que ele entende: {"msg":"1"} / {"msg":"0"}
snprintf(msg, sizeof(msg), "{\"msg\":\"%d\"}", (int)releOn);
emqx.publish(EMQX_PUB_TOPIC, msg);
Serial.print("[UBI] Recebido - Comando Relé: ");
Serial.println(buf);
Serial.print("[EMQX] Publicado - Comando Relé: ");
Serial.println(msg);
}
// ---- Conexão WiFi -----------------------------------
void connectWiFi() {
Serial.print("[WiFi] Conectando...");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\n[WiFi] Conectado!!!");
}
// ---- Conexão EMQX (MQTTX WEB / EMQX) ------------------
void connectEMQX() {
emqx.setServer(EMQX_BROKER, EMQX_PORT);
emqx.setCallback(emqxCallback);
while (!emqx.connected()) {
Serial.print("[EMQX] Conectando... ");
// Se EMQX_CLIENTID estiver vazio, usa um ID único
if (emqxClientIdStr.length() == 0) {
uint64_t mac = ESP.getEfuseMac();
emqxClientIdStr = "esp32-gian-bridge-emqx-" + String((uint32_t)mac, HEX);
}
const char* cid = (strlen(EMQX_CLIENTID) > 0) ? EMQX_CLIENTID : emqxClientIdStr.c_str();
if (emqx.connect(cid)) {
Serial.println("conectado!");
emqx.subscribe(EMQX_SUB_TOPIC);
Serial.print("[EMQX] Subscrito em: ");
Serial.println(EMQX_SUB_TOPIC);
} else {
Serial.print("falhou (rc=");
Serial.print(emqx.state());
Serial.println("). Tentando novamente em 2s...");
delay(2000);
}
}
}
// ---- Conexão Ubidots ---------------------------------
void connectUBI() {
ubi.setServer(UBI_BROKER, UBI_PORT);
ubi.setCallback(ubiCallback);
while (!ubi.connected()) {
Serial.println("[UBI] Conectando...");
// Se UBI_CLIENTID estiver vazio, usa um ID único
if (ubiClientIdStr.length() == 0) {
uint64_t mac = ESP.getEfuseMac();
ubiClientIdStr = "esp32-gian-bridge-ubi-" + String((uint32_t)mac, HEX);
}
const char* cid = (strlen(UBI_CLIENTID) > 0) ? UBI_CLIENTID : ubiClientIdStr.c_str();
// Ubidots MQTT: user=token, pass=""
if (ubi.connect(cid, UBI_TOKEN, "")) {
Serial.println("[UBI] Conectado!!!");
ubi.subscribe(UBI_SUB_TOPIC);
Serial.print("[UBI] Subscrito em: ");
Serial.println(UBI_SUB_TOPIC);
} else {
Serial.print("[UBI] falhou (rc=");
Serial.print(ubi.state());
Serial.println("). Tentando novamente em 2s...");
delay(2000);
}
}
}
// ---- Setup ------------------------------------------
void setup() {
Serial.begin(115200);
connectWiFi();
connectEMQX();
connectUBI();
}
// ---- Loop -------------------------------------------
void loop() {
if (!emqx.connected())
connectEMQX();
if (!ubi.connected())
connectUBI();
emqx.loop();
ubi.loop();
unsigned long now = millis();
// Envia para o Ubidots, periodicamente, os últimos valores recebidos do EMQX
if (now - lastMsg > 3000) {
lastMsg = now;
snprintf(msg, sizeof(msg),
"{\"temperatura\": %.2f, \"umidade\": %.1f, \"lux\": %.1f, \"rele\": %d}",
temperatura, umidade, lux, (int)releOn);
ubi.publish(UBI_PUB_TOPIC, msg);
Serial.print("[UBI] Publicado: ");
Serial.println(msg);
}
}