,
Um recurso muito prático no campo da IoT é a capacidade de programar um microcontrolador conectado, como um ESP8266, via WiFi. Esta técnica é designada por Programação Over-The-Air (OTA).
Hardware
- NodeMCU ESP8266
- Cabo USB A macho
- Computador
- Rede WiFi
Princípio de funcionamento
Em princípio, o ESP8266 NodeMCU é programado através da porta USB. O computador comunica o programa ao microcontrolador. Quando dois dispositivos estão ligados à mesma rede WiFi, podem comunicar entre si. Assim, é possível carregar código através da rede WiFi sem ter de se ligar a cada microcontrolador.
É igualmente possível carregar um código no NodeMCU quando este está configurado como ponto de acesso WiFi. Neste caso, o computador utilizado para a programação deve estar ligado à rede do NodeMCU.
Adicionar firmware ArduinoOTA
A biblioteca ArduinoOTA está disponível quando se instala o gestor do ESP8266. Para configurar a programação OTA, é necessário instalar o firmware. Para o fazer, pode utilizar o exemplo BasicOTA.ino disponível no IDE Arduino.
Certifique-se de que substitui ssid e password pelos identificadores da sua rede WiFi.
#include <ESP8266WiFi.h> #include <ESP8266mDNS.h> #include <WiFiUdp.h> #include <ArduinoOTA.h> #ifndef STASSID #define STASSID "your-ssid" #define STAPSK "your-password" #endif const char* ssid = STASSID; const char* password = STAPSK; void setup() { Serial.begin(115200); Serial.println("Booting"); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); while (WiFi.waitForConnectResult() != WL_CONNECTED) { Serial.println("Connection Failed! Rebooting..."); delay(5000); ESP.restart(); } // Port defaults to 8266 // ArduinoOTA.setPort(8266); // Hostname defaults to esp8266-[ChipID] // ArduinoOTA.setHostname("myesp8266"); // No authentication by default // ArduinoOTA.setPassword("admin"); // Password can be set with it's md5 value as well // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3 // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3"); ArduinoOTA.onStart([]() { String type; if (ArduinoOTA.getCommand() == U_FLASH) { type = "sketch"; } else { // U_FS type = "filesystem"; } // NOTE: if updating FS this would be the place to unmount FS using FS.end() Serial.println("Start updating " + type); }); ArduinoOTA.onEnd([]() { Serial.println("\nEnd"); }); ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { Serial.printf("Progress: %u%%\r", (progress / (total / 100))); }); ArduinoOTA.onError([](ota_error_t error) { Serial.printf("Error[%u]: ", error); if (error == OTA_AUTH_ERROR) { Serial.println("Auth Failed"); } else if (error == OTA_BEGIN_ERROR) { Serial.println("Begin Failed"); } else if (error == OTA_CONNECT_ERROR) { Serial.println("Connect Failed"); } else if (error == OTA_RECEIVE_ERROR) { Serial.println("Receive Failed"); } else if (error == OTA_END_ERROR) { Serial.println("End Failed"); } }); ArduinoOTA.begin(); Serial.println("Ready"); Serial.print("IP address: "); Serial.println(WiFi.localIP()); } void loop() { ArduinoOTA.handle(); }

Tome nota do endereço IP local do aparelho (aqui: 192.168.1.78).
Quando este código tiver sido carregado através de comunicação série, poderá carregar um código através de Wifi. Prima o botão RST ou EN no seu ESP e reinicie o Arduino IDE.
Modificar o seu programa antes de o carregar
Colocamos o código de inicialização na função initOTA(). Assim, será fácil copiá-lo para outros projectos. E acrescentamos um ecrã na porta série para verificar se o código foi modificado.
ATENÇÃO: O código de inicialização do ArduinoOTA deve estar presente em todos os códigos que carregar ou perderá a capacidade de efectuar transmissões aéreas.
#include <ESP8266WiFi.h> #include <ESP8266mDNS.h> #include <WiFiUdp.h> #include <ArduinoOTA.h> const char* ssid = "*******"; const char* password = "********"; unsigned long previousMillis; void setup() { Serial.begin(115200); Serial.println("Booting"); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); while (WiFi.waitForConnectResult() != WL_CONNECTED) { Serial.println("Connection Failed! Rebooting..."); delay(5000); ESP.restart(); } initOTA(); Serial.println("Ready"); Serial.print("IP address: "); Serial.println(WiFi.localIP()); } void loop() { ArduinoOTA.handle(); if (millis() - previousMillis >= 500) { previousMillis = millis(); Serial.println(F("Code has been update")); } } void initOTA() { // Port defaults to 8266 // ArduinoOTA.setPort(8266); // Hostname defaults to esp8266-[ChipID] // ArduinoOTA.setHostname("myesp8266"); // No authentication by default // ArduinoOTA.setPassword("admin"); // Password can be set with it's md5 value as well // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3 // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3"); ArduinoOTA.onStart([]() { String type; if (ArduinoOTA.getCommand() == U_FLASH) { type = "sketch"; } else { // U_FS type = "filesystem"; } // NOTE: if updating FS this would be the place to unmount FS using FS.end() Serial.println("Start updating " + type); }); ArduinoOTA.onEnd([]() { Serial.println("\nEnd"); }); ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { Serial.printf("Progress: %u%%\r", (progress / (total / 100))); }); ArduinoOTA.onError([](ota_error_t error) { Serial.printf("Error[%u]: ", error); if (error == OTA_AUTH_ERROR) { Serial.println("Auth Failed"); } else if (error == OTA_BEGIN_ERROR) { Serial.println("Begin Failed"); } else if (error == OTA_CONNECT_ERROR) { Serial.println("Connect Failed"); } else if (error == OTA_RECEIVE_ERROR) { Serial.println("Receive Failed"); } else if (error == OTA_END_ERROR) { Serial.println("End Failed"); } }); ArduinoOTA.begin(); }
Depois de ter modificado o seu código, em “Ferramenta> Porta”, seleccione a sua placa entre as portas de rede. (Se a porta de rede não for apresentada, consulte a secção seguinte)

Pode então carregar o seu código como faria com a comunicação em série.

Seleccione novamente a porta série e abra o monitor série para verificar se o código foi modificado.

Se a porta de rede não for exibida no IDE do Arduino
Se a porta de rede não estiver presente nas opções do Arduino IDE, terá de fazer um pequeno trabalho. É necessário ir ao Centro de Rede e Partilha

De seguida, vá a “Modificar parâmetros do mapa”.
Clique com o botão direito do rato na sua rede e vá para propriedades
Pode então desmarcar a opção “Protocolo Internet versão 6 (TCP)”.

Se voltar ao Arduino IDE, em “Tool > Port” (Ferramenta > Porta) deve ver a opção de porta de rede.
Pode verificar novamente o IPv6 assim que a sua porta de rede for reconhecida.
Bónus: visualização de mensagens de série OTA
A possibilidade de carregar um programa via WiFi é muito útil, mas vale a pena notar que se perde a capacidade de depurar com o monitor de série. É possível criar uma interface Web que permita visualizar as informações do ESP8266 NodeMCU.
Aqui veremos como usar a biblioteca RemoteDebug para se conectar ao microcontrolador via telnet e recuperar as mensagens enviadas.
- Comece por instalar a biblioteca descarregando o ficheiro ZIP ou através do gestor de bibliotecas.

- Criar um objecto RemoteDebug Debug; depois de incluir o objecto
- Inicialize a depuração com Debug.begin(“ESP8266”);
- Em seguida, substitua todos os Serial.print por Debug.print
#include <ESP8266WiFi.h> #include <ESP8266mDNS.h> #include <WiFiUdp.h> #include <ArduinoOTA.h> #include <RemoteDebug.h> const char* ssid = "******"; const char* password = "*******"; RemoteDebug Debug; unsigned long previousMillis; void setup() { Serial.begin(115200); Serial.println("Booting"); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); while (WiFi.waitForConnectResult() != WL_CONNECTED) { Serial.println("Connection Failed! Rebooting..."); delay(5000); ESP.restart(); } // init remote debug Debug.begin("ESP8266"); initOTA(); Serial.println("Ready"); Serial.print("IP address: "); Serial.println(WiFi.localIP()); } void loop() { ArduinoOTA.handle(); Debug.handle(); if (millis() - previousMillis >= 500) { previousMillis = millis(); Debug.println(F("Code has been update")); } } void initOTA() { // Port defaults to 8266 // ArduinoOTA.setPort(8266); // Hostname defaults to esp8266-[ChipID] //ArduinoOTA.setHostname("ESP8266"); // No authentication by default // ArduinoOTA.setPassword("admin"); // Password can be set with it's md5 value as well // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3 // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3"); ArduinoOTA.onStart([]() { String type; if (ArduinoOTA.getCommand() == U_FLASH) { type = "sketch"; } else { // U_FS type = "filesystem"; } // NOTE: if updating FS this would be the place to unmount FS using FS.end() Serial.println("Start updating " + type); }); ArduinoOTA.onEnd([]() { Serial.println("\nEnd"); }); ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { Serial.printf("Progress: %u%%\r", (progress / (total / 100))); }); ArduinoOTA.onError([](ota_error_t error) { Serial.printf("Error[%u]: ", error); if (error == OTA_AUTH_ERROR) { Serial.println("Auth Failed"); } else if (error == OTA_BEGIN_ERROR) { Serial.println("Begin Failed"); } else if (error == OTA_CONNECT_ERROR) { Serial.println("Connect Failed"); } else if (error == OTA_RECEIVE_ERROR) { Serial.println("Receive Failed"); } else if (error == OTA_END_ERROR) { Serial.println("End Failed"); } }); ArduinoOTA.begin(); }
Para visualizar as mensagens enviadas via RemoteDebug, vamos utilizar o software PuTTy que já vimos várias vezes. Para esta aplicação, vamos configurar o PuTTy no telnet usando o endereço IP obtido do monitor serial.

