[ESP8266] Arduino OTA (Over The Air) Flashing

Arduino OTA (Over The Air) adalah sebuah fitur pemrograman dari Arduino tanpa menggunakan komunikasi kabel, melainkan dengan menggunakan jaringan WiFi.
Dengan fitur ini, proses pemrograman/flashing dapat dilakukan secara wireless dengan menggunakan komuniksi TCP/IP.
Jika firmware OTA sudah aktif dalam ESP8266 anda, gunakan aplikasi ini untuk mengupload firmware baru : Bitbumper_FlashESP8266_OTA. Tentunya firmware yang baru itu harus mempunyai fitur OTA juga agar selanjutnya dapat diupdate via TCP/IP.

Firmware OTA ini harus ditanamkan dalam firmware sebelum fitur OTA dapat digunakan. Tentunya bila fitur OTA belum aktif, maka pemrograman harus dilakukan menggunakan kabel USBTTL tidak bisa via TCP/IP.
Berikut ini adalah Script untuk versi paling dasar untuk mengaktifkan OTA seperti dibawah ini:

#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>

#ifndef STASSID
#define STASSID "NAMA-WIFI"
#define STAPSK  "PSWD-WIFI"
#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();
  }

  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();
}

Jika script diatas adalan versi Basic dari OTA, maka script berikut ini adalah script versi Advanced. Dengan script OTA dibawah ini, anda bisa menampilkan informasi proses flashing di layar OLED SSD1306. Display OLED SSD1306 dihubungkan ke ESP8266 (NodeMCU) melalui pin berikut:
D1 (GPIO5) digunakan untuk SCL Display SSD1306
D2 (GPIO4) digunakan untuk SDA Display SSD1306

Silahkan copy-paste kode berikut ini kedalam Arduino IDE Anda:

#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <ESP8266WiFi.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <elapsedMillis.h>

//--- LOGO AZKATECH 128 x 64
static const uint8_t logo[1024] = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x31, 0x80, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x79, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xb3, 0x00, 0x36, 0x6c, 0x00, 0xcd, 0x80, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0xb3, 0x00, 0x36, 0x6c, 0x00, 0xcd, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x9e, 0x00, 0x36, 0x6c, 0x00, 0x79, 0x80, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0x8c, 0x00, 0x36, 0x6c, 0x00, 0x31, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0xff, 0xff, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0xff, 0xff, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0xc0, 0x03, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x1f, 0xc0, 0x03, 0xf8, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x1f, 0xff, 0xff, 0xf8, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x1f, 0xff, 0xff, 0xf8, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x1c, 0x00, 0x00, 0x38, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x1c, 0x00, 0x00, 0x38, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0xfc, 0x00, 0x00, 0x3f, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0xfc, 0x6d, 0xb6, 0x3f, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x8f, 0xcc, 0x6d, 0xb6, 0x33, 0xf1, 0x80, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0x8f, 0xcc, 0x00, 0x00, 0x33, 0xf1, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0xcc, 0x36, 0x6c, 0x33, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0x8f, 0xcc, 0x36, 0x6c, 0x33, 0xf1, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x8f, 0xcc, 0x00, 0x00, 0x33, 0xf1, 0x80, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0xcc, 0x6d, 0xb6, 0x33, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0xcc, 0x6d, 0xb6, 0x33, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0x8f, 0xcc, 0x00, 0x00, 0x33, 0xf1, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x8f, 0xcc, 0x36, 0x6c, 0x33, 0xf1, 0x80, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0xcc, 0x36, 0x6c, 0x33, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x8f, 0xcc, 0x00, 0x00, 0x33, 0xf1, 0x80, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0x8f, 0xcc, 0x6d, 0xb6, 0x33, 0xf1, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0xfc, 0x6d, 0xb6, 0x3f, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0xfc, 0x00, 0x00, 0x3f, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x1c, 0x00, 0x00, 0x38, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x1c, 0x00, 0x00, 0x38, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x1f, 0xff, 0xff, 0xf8, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x1f, 0xff, 0xff, 0xf8, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x1f, 0xc0, 0x03, 0xf8, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0xc0, 0x03, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0xff, 0xff, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0xff, 0xff, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x8c, 0x00, 0x36, 0x6c, 0x00, 0x31, 0x80, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0x9e, 0x00, 0x36, 0x6c, 0x00, 0x79, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xb3, 0x00, 0x36, 0x6c, 0x00, 0xcd, 0x80, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0xb3, 0x00, 0x36, 0x6c, 0x00, 0xcd, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x79, 0x80, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x31, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

Adafruit_SSD1306 oled1(128, 64, &Wire, -1); 

#if (SSD1306_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

String ssid = "NAMA-WIFI";
String pass = "PSWD-WIFI";
bool startOTA = false;
elapsedSeconds timerWiFi;

WiFiClient client;

void setup() 
{
  WiFi.mode(WIFI_STA);
  oled1.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  oled1.clearDisplay();
  oled1.setTextSize(1);
  oled1.setTextColor(WHITE);
  oled1.drawRect(1, 1, oled1.width()-1, oled1.height()-1, SSD1306_WHITE);
  oled1.drawLine(1,22,oled1.width(),22, SSD1306_WHITE);
  oled1.clearDisplay();
  oled1.drawBitmap(0,0, logo, 128, 64, 1);
  oled1.setCursor(10,56);
  oled1.println(" WWW.AZKATECH.COM");
  oled1.display();
  delay(3000);

  WiFi.begin(ssid.c_str(), pass.c_str()); 
  oled1.clearDisplay();
  oled1.setCursor(1,1);
  oled1.setTextSize(1);
  oled1.println("Menghubungkan WiFi");
  oled1.setCursor(1,11);
  oled1.print("SSID: ");
  oled1.println(ssid);
  oled1.setCursor(0,17);
  oled1.display();

  int scan = 0;
  while ( WiFi.status() != WL_CONNECTED ) 
  {
    if(scan > 4) scan = 0;
    delay (200);
    scan++;
    oled1.print(".");
    oled1.display();
    delay(500);
    if(timerWiFi >= 60) 
    {
      oled1.println(".");
      oled1.print("TIDAK TERHUBUNG!!!");
      oled1.display();
      return;
    }
  }

  delay(500);
  oled1.setTextSize(1);
  oled1.setTextWrap(false);

  IPAddress ip = WiFi.localIP();
  if(ip) {
    oled1.clearDisplay();
    oled1.setCursor(1,1);
    oled1.println("Terhubung ke WiFi");
    oled1.setCursor(1,11);
    oled1.print("SSID: ");
    oled1.println(ssid);
    oled1.setCursor(1,21);
    oled1.print("IP: ");
    oled1.println(ip);
    oled1.display();
  }
  delay(3000);
  
  ArduinoOTA.onStart([]() {
    startOTA = true;
    oled1.clearDisplay();
    oled1.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
    oled1.setFont();
    oled1.setTextSize(1);
    oled1.setCursor(1, 1);
    oled1.println("OTA Starting...");
    oled1.display();
  });
  ArduinoOTA.onEnd([]() {
    oled1.setCursor(1, 21);
    oled1.println("OTA Finished...");
    oled1.display();
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    char persen [10];
    dtostrf (progress, 8, 0, persen); 
    oled1.clearDisplay();
    oled1.setCursor(1, 1);
    oled1.println("OTA Starting...");
    oled1.setCursor(1, 11);
    oled1.println("Progress: "+String(persen));
    oled1.display();
  });
  ArduinoOTA.onError([](ota_error_t error) {
    oled1.clearDisplay();
    oled1.setTextSize(2);
    oled1.setCursor(1, 31);
    oled1.println("OTA ERROR");
    oled1.display();
  });

  ArduinoOTA.setHostname("ESP_OTA"); 
  ArduinoOTA.begin();
  oled1.clearDisplay();
}


void loop()
{
  ArduinoOTA.handle();
  if(!startOTA)
  {
    oled1.drawBitmap(0,0, logo, 128, 64, 1);
    oled1.fillRoundRect(1,54,126,10,2,1);
    oled1.setTextSize(1);
    oled1.setTextColor(SSD1306_BLACK);
    oled1.setCursor(3,55);
    oled1.print(F("OTA: "));
    oled1.print(WiFi.localIP());
    oled1.display();
  }
}