// Dispositivo: Atuador // Versão Firmware: 8 // Ultima atualização: 29/11/2024 // Atualização: Implementado MQTT #include #include "C:\ZendionInc\agrobot_base\Firmware\Modulos\MqttService.h" #include "C:\ZendionInc\agrobot_base\Firmware\Modulos\WifiService.h" #include "C:\ZendionInc\agrobot_base\Firmware\Modulos\EepromService.h" #include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SerialService.h" #include "C:\ZendionInc\agrobot_base\Firmware\Modulos\Utils.h" #include "C:\ZendionInc\agrobot_base\Firmware\Modulos\Pinout.h" #include "C:\ZendionInc\agrobot_base\Firmware\Modulos\ReleModel.h" #include "C:\ZendionInc\agrobot_base\Firmware\Modulos\BombaPressurizadoraModel.h" #include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorFluxoModel.h" #include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorMassaModel.h" #include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorPressaoModel.h" // Configurações do IP estático IPAddress local_IP(192, 168, String(WIFI_FAIXA).toInt(), 13); // IP fixo para o ESP IPAddress gateway(192, 168, String(WIFI_FAIXA).toInt(), 1); // Gateway padrão IPAddress subnet(255, 255, 255, 0); // Máscara de sub-rede IPAddress primaryDNS(8, 8, 8, 8); // Servidor DNS primário (opcional) // Instancia o serviço MQTT MqttService mqttService; #define D_Code Atu #define VERSION 8 const String Mod_ID = "Atu"; #define _pinoLED RGB_BUILTIN long _baudRate = 115200; bool Conectado = false; bool Verificando = false; int _TaxaAmostragem = 1000; volatile bool RequisitarDados = false; int latenciaLoop = 0; std::vector listaBicos; std::vector listaBombas; std::vector listaSensoresFluxo; std::vector listaSensoresMassa; std::vector listaSensoresPressao; void InicializarComunicacaoMQTT(bool RenovarConexao) { if (RenovarConexao) { mqttService.unsubscribe(TopicoRecepcao); delay(1000); } mqttService.setModID(Mod_ID); mqttService.InicializarComunicacaoMqtt(); mqttService.setMessageCallback(ProcessarProtocolo); } void setup() { Serial.begin(_baudRate); InicializarConexaoWifi(local_IP, gateway, subnet, primaryDNS); if (!WifiIsConnected) { connectToWiFi(); if (WifiIsConnected) { PrintTela("Conectado com sucesso"); } else { PrintTela("Erro ao se conectar ao wifi"); ESP.restart(); } } delay(100); if (WifiIsConnected) { InicializarComunicacaoMQTT(false); } } void loop() { unsigned long startLoop = millis(); if (!RequisitarDados) { enviarLogsPeriodicamente(); } mqttService.loop(); for (auto* bomba : listaBombas) { bomba->Loop(); } for (auto* sensor : listaSensoresFluxo) { sensor->Loop(); } delay(1); latenciaLoop = millis() - startLoop; } // Função para enviar logs do sensor periodicamente via MQTT unsigned long ultimoEnvioLogs = 0; const unsigned long intervaloEnvioLogs = 1000; // 1 segundo void enviarLogsPeriodicamente() { unsigned long tempoAtual = millis(); // Verifica se o intervalo de 5 segundos já passou if (tempoAtual - ultimoEnvioLogs >= intervaloEnvioLogs) { ultimoEnvioLogs = tempoAtual; // Atualiza o tempo do último envio enviarDadosSensores(); // Chama o método que já envia os dados do sensor via MQTT } } void enviarDadosSensores() { if (Conectado && !Verificando) { PrintTela("Atualizando dados dos sensores..."); // Aferir dados dos sensores for (auto* bico : listaBicos) { bico->AtualizarLeitura(); } // Aferir dados dos sensores for (auto* sensor : listaSensoresFluxo) { sensor->AtualizarLeitura(); } // Aferir dados dos sensores for (auto* sensor : listaSensoresMassa) { sensor->RequisitarDados(); } // Aferir dados dos sensores for (auto* sensor : listaSensoresPressao) { sensor->RequisitarDados(); } String jsonString = MontarMensagemSensores() + String(EndLine); mqttService.EnviarDados(Mod_ID, jsonString); } } String MontarMensagemSensores() { // Criação de um objeto JSON dinâmico com tamanho adequado DynamicJsonDocument jsonDoc(2048); // Adicionar campos gerais jsonDoc["Conectado"] = Conectado; jsonDoc["Mod_ID"] = Mod_ID; jsonDoc["QualidadeWifi"] = WiFi.RSSI(); jsonDoc["LatenciaLoop"] = latenciaLoop; // Array JSON para bicos pulverizadores JsonArray bicosArray = jsonDoc.createNestedArray("BicosPulverizadores"); for (const auto* sensor : listaBicos) { JsonObject sensorData = bicosArray.createNestedObject(); sensorData["Id"] = sensor->_ID; sensorData["Iniciado"] = sensor->Iniciado; sensorData["Leitura"] = sensor->_Status; } // Array JSON para bombas pressurizadoras JsonArray bombasArray = jsonDoc.createNestedArray("BombasPressurizadoras"); for (const auto* sensor : listaBombas) { JsonObject sensorData = bombasArray.createNestedObject(); sensorData["Id"] = sensor->_ID; sensorData["Iniciado"] = sensor->Iniciado; sensorData["Estado"] = sensor->EstadoLeitura; sensorData["Potencia"] = sensor->PercentualPotenciaLeitura; sensorData["PressaoSP"] = sensor->_PressaoSP; sensorData["Pressao"] = sensor->sensorPressao->Pressao; } // Array JSON para sensores de fluxo JsonArray sensoresFluxoArray = jsonDoc.createNestedArray("SensoresFluxo"); for (const auto* sensor : listaSensoresFluxo) { JsonObject sensorData = sensoresFluxoArray.createNestedObject(); sensorData["Id"] = sensor->_ID; sensorData["Iniciado"] = sensor->Iniciado; sensorData["Pulsos"] = sensor->_PulsosLeitura; sensorData["Periodo"] = sensor->_PeriodoTotalLeitura; } // Array JSON para sensores de massa JsonArray sensoresMassaArray = jsonDoc.createNestedArray("SensoresMassa"); for (const auto* sensor : listaSensoresMassa) { JsonObject sensorData = sensoresMassaArray.createNestedObject(); sensorData["Id"] = sensor->_ID; sensorData["Iniciado"] = sensor->Iniciado; sensorData["Leitura"] = sensor->leituraMassa; } // Array JSON para sensores de pressao JsonArray sensoresPressaoArray = jsonDoc.createNestedArray("SensoresPressao"); for (const auto* sensor : listaSensoresPressao) { JsonObject sensorData = sensoresPressaoArray.createNestedObject(); sensorData["Id"] = sensor->_ID; sensorData["Iniciado"] = sensor->Iniciado; sensorData["Pressao"] = sensor->Pressao; sensorData["Leitura"] = sensor->leitura; } // Serializa o JSON para uma string String jsonString; serializeJson(jsonDoc, jsonString); int messageSize = jsonString.length(); PrintTela("Tamanho da mensagem: ", false); PrintTela((String)messageSize); return jsonString; } void ProcessarProtocolo(ProtocoloSerial Mensagem) { switch (Mensagem.funcao) { case Chk: ProcessarChk(Mensagem); break; case Cfg: ProcessarCfg(Mensagem); break; case Cmd: ProcessarCmd(Mensagem); break; case Req: ProcessarReq(Mensagem); break; } if (Mensagem.idMensagem > 0) { EnviarDadosSerial(Mod_ID, MontarProtocoloMensagemRecebida(Mensagem.idMensagem)); } } void ProcessarChk(ProtocoloSerial Mensagem) { Verificando = true; mqttService.EnviarDados(Mod_ID, MontarProtocoloVerificacao(D_Code, VERSION, Conectado)); delay(2000); Verificando = false; } void ProcessarCfg(ProtocoloSerial Mensagem) { std::vector Partes = SplitString(Mensagem.protocolo, SplitParams); T_Code Tipo = (T_Code)(Partes[0].toInt()); if (Tipo == Mod) { bool Conectar = Partes[1] == "1"; _TaxaAmostragem = Partes[2].toInt(); RequisitarDados = Partes[3] == "1"; vTaskDelay(pdMS_TO_TICKS(100)); Conectado = Conectar; Verificando = false; enviarDadosSensores(); } else { S_Code componente = (S_Code)Partes[1].toInt(); String config = Partes[2]; switch (componente) { case sBIC: { Rele::InicializarLista(listaBicos, config, Mod_ID); break; } case sBMB: { BombaPressurizadora::InicializarLista(listaBombas, config, Mod_ID, listaSensoresPressao); break; } case sFLX: { SensorFluxo::InicializarLista(listaSensoresFluxo, config, Mod_ID); break; } case sMAS: { SensorMassa::InicializarLista(listaSensoresMassa, config, Mod_ID); break; } case sPRS: { SensorPressao::InicializarLista(listaSensoresPressao, config, Mod_ID); break; } } } } void ProcessarCmd(ProtocoloSerial Mensagem) { std::vector Partes = SplitString(Mensagem.protocolo, SplitParams); String ID = Partes[0]; S_Code componente = (S_Code)Partes[1].toInt(); switch (componente) { case sBIC: { for (auto* _rele : listaBicos) { if (_rele->_ID == ID) { Estado novoEstado = (Estado)Partes[2].toInt(); _rele->AtualizarStatus(novoEstado); } } break; } case sBMB: { for (auto* _bomba : listaBombas) { if (_bomba->_ID == ID) { _bomba->_EstadoControle = (Estado)(Partes[2].toInt()); _bomba->_PressaoSP = Partes[3].toDouble(); _bomba->AlterarStatusBomba(); } } break; } } } void ProcessarReq(ProtocoloSerial Mensagem) { enviarDadosSensores(); }