agrobot_base/Firmware/Modulos/MqttService.h

181 lines
5.7 KiB
C++

#include "SerialService.h"
#include <WiFi.h>
#include <PubSubClient.h>
#ifndef MqttService_h
#define MqttService_h
#define WIFI_FAIXA "100"
const String TopicoRecepcao = "disp/tx/";
const String TopicoTransmissao = "disp/rx/";
unsigned long ultimaTentativaConexao = 0; // Tempo da última tentativa de conexão
const unsigned long intervaloTentativa = 5000; // 5 segundos
class MqttService {
private:
const char* server = "192.168." WIFI_FAIXA ".105";
int port = 1883;
const char* user = "";
const char* password = "";
String mqtt_mod_id; // Alterado para String
WiFiClient wifiClient;
PubSubClient mqttClient;
// Ponteiros para funções de callback
void (*messageCallback)(ProtocoloSerial) = nullptr;
public:
bool MqttIsConnected = false;
MqttService() : mqttClient(wifiClient) {
mqttClient.setServer(server, port);
mqttClient.setBufferSize(2048);
mqttClient.setCallback([this](char* topic, byte* payload, unsigned int length) {
this->processMessage(topic, payload, length);
});
}
void setModID(const String& mqtt_id) {
mqtt_mod_id = mqtt_id; // Atribui diretamente a String
}
void setMessageCallback(void (*callback)(ProtocoloSerial)) {
messageCallback = callback;
}
bool InicializarComunicacaoMqtt() {
// Verifica se já passou o intervalo necessário para uma nova tentativa
if (millis() - ultimaTentativaConexao < intervaloTentativa) {
PrintTela("Aguardando para próxima tentativa de conexão MQTT...");
return MqttIsConnected; // Retorna o estado atual sem tentar reconectar
}
ultimaTentativaConexao = millis(); // Atualiza o tempo da última tentativa
connect();
if (MqttIsConnected) {
PrintTela("Tamanho máximo de mensagens: " + String(mqttClient.getBufferSize()));
LimparMensagensRetidas(TopicoRecepcao + mqtt_mod_id); // Limpa mensagens retidas
subscribe(TopicoRecepcao);
}
return MqttIsConnected;
}
void connect() {
while (!mqttClient.connected()) {
PrintTela("Conectando ao broker MQTT...", false);
//if (mqttClient.connect(mqtt_mod_id.c_str(), user, password)) {
if (mqttClient.connect(mqtt_mod_id.c_str())) {
PrintTela("Conectado ao broker MQTT!");
MqttIsConnected = true;
} else {
PrintTela("Falha ao conectar, rc=", false);
PrintTela((String)mqttClient.state());
MqttIsConnected = false;
delay(2000);
}
}
}
void LimparMensagensRetidas(const String& topico) {
if (mqttClient.connected()) {
// Publica uma mensagem vazia com o flag Retain para limpar mensagens retidas
if (mqttClient.publish(topico.c_str(), "", true)) {
Serial.println("Mensagem retida limpa no tópico: " + topico);
} else {
Serial.println("Falha ao limpar mensagem retida no tópico: " + topico);
}
} else {
Serial.println("Broker MQTT desconectado, não foi possível limpar mensagens retidas.");
}
}
void subscribe(String topico) {
String fullTopic = topico + mqtt_mod_id; // Concatena o ID ao tópico base
mqttClient.subscribe(fullTopic.c_str());
PrintTela("Inscrito no tópico: ", false);
PrintTela(fullTopic);
}
void unsubscribe(String topico) {
String fullTopic = topico + mqtt_mod_id; // Concatena o ID ao tópico base
mqttClient.unsubscribe(fullTopic.c_str()); // Remove a inscrição de cada tópico
PrintTela("Desinscrito do tópico: ", false);
PrintTela(fullTopic);
}
bool publish(String message) {
String fullTopic = TopicoTransmissao + mqtt_mod_id; // Concatena o ID ao tópico base
// Verifica se está conectado ao broker antes de tentar publicar
if (mqttClient.connected()) {
bool success = mqttClient.publish(fullTopic.c_str(), message.c_str(), true); // Publica a mensagem
if (success) {
PrintTela("Mensagem enviada com sucesso para ", false);
} else {
PrintTela("Falha ao enviar mensagem para ", false);
}
PrintTela(fullTopic, false); // Imprime o tópico completo para verificação
PrintTela(": ", false);
PrintTela(message);
return success;
} else {
PrintTela("Erro: Conexão com o broker MQTT perdida. Tentando reconectar...");
InicializarComunicacaoMqtt(); // Tenta reconectar
return false;
}
}
void loop() {
if (mqttClient.connected()) {
mqttClient.loop();
}
else {
InicializarComunicacaoMqtt();
}
}
void EnviarDados(String Mod_ID, String Mensagem) {
if (MqttIsConnected) {
String ProtocoloEnvio = Mod_ID + SplitMessage + Mensagem;
publish(ProtocoloEnvio);
}
}
// Processa a mensagem recebida e aciona o callback correspondente
void processMessage(char* topic, byte* payload, unsigned int length) {
String topicStr(topic);
String message;
for (unsigned int i = 0; i < length; i++) {
message += (char)payload[i];
}
PrintTela("Mensagem recebida no tópico ", false);
PrintTela(topicStr, false);
PrintTela(": ", false);
PrintTela(message);
if (topicStr == TopicoRecepcao + mqtt_mod_id) {
std::vector<String> Partes = SplitString(message, SplitMessage);
if (Partes.size() == 4) {
ProtocoloSerial objeto;
objeto.idMensagem = Partes[0].toInt();
objeto.Mod_ID = Partes[1];
objeto.funcao = (F_Code)(Partes[2].toInt());
objeto.protocolo = Partes[3];
if (mqtt_mod_id == objeto.Mod_ID && messageCallback) {
messageCallback(objeto);
}
}
}
}
};
#endif