Esta é a segunda e última parte do projeto mostrando como usar o Raspberry Pi para controlar o NodeMCU, e neste projeto você pode controlar as saídas de até cinco NodeMCUs diferentes com uma GUI feita em Python com TKinter.
O controle é feito pela Internet utilizando MQTT, ou seja, o controle pode ser feito de qualquer lugar do mundo com conectividade à Internet. Aqui será mostrado como programar os NodeMCUs de forma a fazerem o proposto.
Material necessário
Além do material listado na parte 1, você precisará de:
- Cinco NodeMCUs (cada um com um cabo micro-USB e fonte 5V para alimentação, com no mínimo 1A de corrente de saída)
- Cinco elementos que deseja acionar / desacionar através do output (LEDs, relés, válvulas solenóides, etc.).
No caso deste projeto, como forma de exemplo, serão controlados cinco LEDs. Dessa forma, serão necessários 5 resistores 220ohm 1/4W e 5 LEDs (cor a sua escolha). - É recomendável o uso de protoboards também (400 ou 830 pontos), conforme necessidade do seu projeto.
Lembre-se que para este projeto você não precisa necessariamente ter 5 placas NodeMCU, você pode usar, por exemplo, o programa com apenas um NodeMCU conectado e fazer os testes necessários.
Recomendações e requisitos
Antes de prosseguir com o projeto para controlar o NodeMCU usando Raspberry Pi, recomendo fortemente que leia nossos artigos listados abaixo. Eles servem de pré-requisito para a programação e uso do NodeMCU conforme é preciso aqui neste projeto.
- Como programar o NodeMCU com IDE Arduino
- Controle e Monitoramento IoT com NodeMCU e MQTT
- Como controlar motor DC com ESP8266 NodeMCU
Portanto, deste ponto em diante, assume-se que seu NodeMCU esteja totalmente operacional, a biblioteca PubSubClient esteja instalada e que seja possível programá-lo pela Arduino IDE.
Circuito esquemático
O circuito esquemático em que cada NodeMCU é envolvido depende muito do que você deseja controlar (LEDs, relés, válvulas solenóides, etc.). Como exemplo, assumirei que LEDs serão controlados.
Sendo assim, deve-se montar cinco circuitos conforme circuito esquemático da figura 1:
O resistor utilizado nos testes tem o valor de 10K, mas você pode usar outros valores.
Código-fonte do programa para controlar o NodeMCU
Conforme foi visto na parte 1 deste projeto para controlar o NodeMCU usando Raspberry Pi, todos os botões da GUI quando clicados fazem com que seja enviado um texto exclusivo (“BT1“, “BT2“, “BT3“, “BT4” e “BT5“) num determinado tópico. Portanto, cada NodeMCU deverá ser capaz de se subescrever ao mesmo tópico o qual o texto é enviado e tratar a mensagem, de modo a “decidir” se a mensagem foi para ele ou não. Dessa forma:
- O NodeMCU 1 deverá alterar o output D0 se receber o texto “BT1” no referido tópico MQTT
- O NodeMCU 2 deverá alterar o output D0 se receber o texto “BT2” no referido tópico MQTT
- O NodeMCU 3 deverá alterar o output D0 se receber o texto “BT3” no referido tópico MQTT
- O NodeMCU 4 deverá alterar o output D0 se receber o texto “BT4” no referido tópico MQTT
- O NodeMCU 5 deverá alterar o output D0 se receber o texto “BT5” no referido tópico MQTT
Desta forma, para cada NodeMCU, deve-se alterar o valor da variável “CmdNodeMCU” para “BT1”, “BT2”, “BT3”, “BT4” ou “BT5”, dependendo do NodeMCU a ser programado (fazendo com que cada NodeMCU obedeça a um texto somente).
Segue abaixo o código-fonte. Preste atenção nos comentários, eles explicam passos importantes de todo o projeto.
//Programa: NodeMCU e MQTT - controle do NodeMCU pela GUI Python //Autor: MakerHero e Pedro Bertoleti #include <ESP8266WiFi.h> // Importa a Biblioteca ESP8266WiFi #include <PubSubClient.h> // Importa a Biblioteca PubSubClient //defines: //defines de id mqtt e tópicos para publicação e subscribe #define TOPICO_SUBSCRIBE "MQTTDisplayRaspPi" //tópico MQTT de escuta. //ATENÇÃO: deve ser o mesmo tópico de publish utilizado na Raspberry PI!!! #define ID_MQTT "NodeMCUGUIPython" //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). //defines - mapeamento de pinos do NodeMCU #define D0 16 #define D1 5 #define D2 4 #define D3 0 #define D4 2 #define D5 14 #define D6 12 #define D7 13 #define D8 15 #define D9 3 #define D10 1 // WIFI const char* SSID = "SSID"; // SSID / nome da rede WI-FI que deseja se conectar const char* PASSWORD = "SENHA"; // Senha da rede WI-FI que deseja se conectar // MQTT const char* BROKER_MQTT = "iot.eclipse.org"; //URL do broker MQTT que se deseja utilizar int BROKER_PORT = 1883; // Porta do Broker MQTT //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 char CmdNodeMCU[3] = {'B','B', 'B'}; //ATENÇÃO: troque o "BBB" por um dos códigos enviados pela Raspberry PI ("BT1", "BT2", "BT3", "BT4" ou "BT5"), // de modo que cada NodeMCU "espere" apenas por um deles //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); /* * Implementações das funções */ void setup() { //inicializações: InitOutput(); initSerial(); initWiFi(); initMQTT(); } //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) { char MsgRecebida[3]; //se a mensagem não tem três caracteres (ou seja, não é "BT1", "BT2", "BT3", "BT4" ou "BT5"), //automaticamente ela é inválida. Nesse caso, nada mais é feito com a mensagem recebida. if (length != 3) return; //obtem a string do payload recebido for(int i = 0; i < length; i++) MsgRecebida[i] = (char)payload[i]; //avalia se a mensagem é para este NodeMCU if (memcmp(MsgRecebida,CmdNodeMCU,3) == 0) { if (EstadoSaida == '0') { digitalWrite(D0,HIGH); EstadoSaida = '1'; } else { digitalWrite(D0,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: inicializa o output em nível lógico baixo //Parâmetros: nenhum //Retorno: nenhum void InitOutput(void) { pinMode(D0, OUTPUT); digitalWrite(D0, LOW); EstadoSaida = '0'; } //programa principal void loop() { //garante funcionamento das conexões WiFi e ao broker MQTT VerificaConexoesWiFIEMQTT(); //keep-alive da comunicação com broker MQTT MQTT.loop(); }
Projeto em ação!
Agora, basta juntar tudo e comandar os outputs pela GUI na Raspberry PI! Veja abaixo um gif animado mostrando o projeto em ação, utilizando um NodeMCU:
Gostou do projeto para controlar o NodeMCU usando Raspberry Pi? Deixe seu comentário logo abaixo.
Olá, parabéns pelo tutorial, muito útil e didático. Para o meu projeto de TCC estou tentado a usar essa comunicação entre o ESP32 e o Raspberry Pi Zero W, estes que contém módulo wifi embutidos e são muito semelhantes aos que foram utilizados nesse tutorial. Então gostaria de saber quais as mudanças de código necessárias para utilizar o ESP32 no lugar do ESP8266?
Cassio, bom dia e obrigado pelos elogios.
Para adaptar o código do ESP8266 para o ESP32, eu ACHO (digo acho pois estou sem ESP8266 e ESP32 perto de mim nesse momento) que basta fazer o seguinte:
1- Trocar a linha:
#include // Importa a Biblioteca ESP8266WiFi
Pela linha:
#include
2- Modificar as chamadas de:
digitalWrite(D0,HIGH);
digitalWrite(D0,LOW);
Trocando D0 pelo GPIO do ESP32 que deseja que o LED fique (isso variará de acordo com seu projeto).
Atenciosamente,
Pedro Bertoleti
Meus parabéns para mais um excelente artigo da série sobre NodeMCU. Venho acompanhando todos desde o início.
Sobre o acesso a rede externa, eu tenho uma dúvida.
Se além do normal, que é o WiFi.begin(SSID, PASSWORD), para se acessar ela for necessária autenticação via proxy, é possível usar o NodeMCU nestas condições? Pois num ambiente doméstico esta autenticação normalmente não é necessária, mas num ambiente comercial e/ou industrial este é um requisito de segurança de rede.
PS. Eu me formei em engenharia no outro lado da Serra da Mantiqueira, na Unifei, em Itajubá.
Angelo, muito obrigado por acompanhar os artigos e pelos elogios!
Entendi seu problema. Infelizmente, eu nunca cheguei ao ponto de precisar utilizar o NodeMCU com autenticação via proxy. Desculpa não conseguir responder sua pergunta.
Atenciosamente,
Pedro Bertoleti