fbpixel
Etiquetas: ,
5
(2)

Um recurso muito prático no campo da IoT é a capacidade de programar um microcontrolador conectado, como um ESP32, via WiFi. Esta técnica é designada por Programação Over-The-Air (OTA).

Hardware

  • NodeMCU ESP32
  • Computador
  • Rede WiFi

 

Princípio de funcionamento

Em princípio, descarrega-se um programa para o ESP32 NodeMCU através de uma ligação em série à 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 o 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. O código completo é apresentado no final deste tutorial.

 

 

Adicionar firmware ArduinoOTA

A biblioteca ArduinoOTA está disponível quando se instala o gestor do ESP32. 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 <WiFi.h>
#include <ESPmDNS.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();
  }
  
    // Port defaults to 3232
  // ArduinoOTA.setPort(3232);

  // Hostname defaults to esp3232-[MAC]
  //ArduinoOTA.setHostname("esp3232");

  // 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_SPIFFS
        type = "filesystem";

      // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
      Serial.println("Start updating " + type);
    })
    .onEnd([]() {
      Serial.println("\nEnd");
    })
    .onProgress([](unsigned int progress, unsigned int total) {
      Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
    })
    .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();
}

Anote o endereço IP local do aparelho (aqui: 192.168.1.33).

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, caso contrário perderá a capacidade de efetuar transmissões aéreas.

#include <WiFi.h>
#include <ESPmDNS.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 3232
  // ArduinoOTA.setPort(3232);

  // Hostname defaults to esp3232-[MAC]
  ArduinoOTA.setHostname("ESP32");

  // 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_SPIFFS
      type = "filesystem";

    // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
    Serial.println("Start updating " + type);
  })
  .onEnd([]() {
    Serial.println("\nEnd");
  })
  .onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  })
  .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();
}

Una vez que haya modificado su código, en “Herramienta> Puerto”, seleccione su tarjeta entre los puertos de red. (si no aparece el puerto de red, consulte el capítulo siguiente).

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

Em seguida, aceda a “Modificar parâmetros do cartão”.

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 depois de o reiniciar, em “Tool > Port” (Ferramenta > Porta) deve ver a opção de porta de rede apresentada.

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 Wi-Fi é muito útil, mas é preciso notar que se perde a possibilidade de depurar com o monitor de série. É possível criar uma interface Web que permita visualizar as informações do ESP32 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 objeto RemoteDebug Debug; depois de incluir o objeto
  • Inicializar a depuração com Debug.begin(“ESP32”);
  • Em seguida, substitua todos os Serial.print por Debug.print
#include <WiFi.h>
#include <ESPmDNS.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("ESP32");  
  
  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 3232
  // ArduinoOTA.setPort(3232);

  // Hostname defaults to esp3232-[MAC]
  ArduinoOTA.setHostname("ESP32");

  // 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_SPIFFS
      type = "filesystem";

    // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
    Serial.println("Start updating " + type);
  })
  .onEnd([]() {
    Serial.println("\nEnd");
  })
  .onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  })
  .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.

 

Bónus 2: Programação OTA em modo de ponto de acesso

É possível utilizar a rede criada pelo ESP32 NodeMCU em modo Access Point. Para isso, pode descarregar o código seguinte através da porta série. Em seguida, é necessário ligar o computador à rede do NodeMCU para poder descarregar um novo código via WiFi.

#include <WiFi.h>
#include <ESPmDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>

const char *ssid = "AC-ESP32";
const char *passphrase = "123456789";

IPAddress local_IP(192,168,4,22);
IPAddress gateway(192,168,4,9);
IPAddress subnet(255,255,255,0);

unsigned long previousMillis;
void setup() {
 Serial.begin(115200);
 Serial.println("Booting");

 //AP config
 Serial.print("Setting soft-AP configuration ... ");
 Serial.println(WiFi.softAPConfig(local_IP, gateway, subnet) ? "Ready" : "Failed!");
 Serial.print("Setting soft-AP ... ");
 Serial.println(WiFi.softAP(ssid,passphrase) ? "Ready" : "Failed!");
   
 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 via Wifi"));
 }
}
void initOTA() {
 // Port defaults to 3232
 // ArduinoOTA.setPort(3232);
 // Hostname defaults to esp3232-[MAC]
 ArduinoOTA.setHostname("ESP32");
 // 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_SPIFFS
     type = "filesystem";
   // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
   Serial.println("Start updating " + type);
 })
 .onEnd([]() {
   Serial.println("\nEnd");
 })
 .onProgress([](unsigned int progress, unsigned int total) {
   Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
 })
 .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();
}

Fontes

How useful was this post?

Click on a star to rate it!

Average rating 5 / 5. Vote count: 2

No votes so far! Be the first to rate this post.

As you found this post useful...

Follow us on social media!

We are sorry that this post was not useful for you!

Let us improve this post!

Tell us how we can improve this post?