Konstruowanie nowych układów jest zajęciem twórczym, wymagającym sporo czasu. Często udaje się wykonać wersję minimum i z braku czasu pozostawiamy działający układ z planami na jego rozbudowę. Na planach się jednak kończy, bo aktualizacja oprogramowania wymaga demontażu układu, lub wpinania się do niego z laptopem. Istnieje proste rozwiązanie tego problemu, które zaoszczędzi nam czasu i problemów z fizycznym dostępem do układu. Metoda ta nazywa się OTA programming (Over-the-air programming), czyli bezprzewodowa aktualizacja oprogramowania.
Czas na konkrety
W Arduino IDE ESP32 mamy gotowy przykładowy kod umożliwiający aktualizację oprogramowania. Wystarczy z przykładów wybrać ArduinoOTA/BasicOTA, wgrać szkic i gotowe. Minusem tego rozwiązania (przykładowego szkicu) jest to, że OTA jest głównym celem. Możemy dopisać własny fragment kodu, ale robi się z tego niezły "makaron". Proponuję posprzątać w kodzie tak, by OTA działało, ale nie zasłaniało nam właściwego pisanego programu. Wystarczy dodać nowy plik (zakładkę) do projektu. Ja nazwałem ten plik wifiOTA. Jego zawartość zamieszczam poniżej:
#include <WiFi.h>
#include <ESPmDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
const char* ssid = "SSID";
const char* password = "HASŁO";
void beginOTA(){
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("Connection Failed! Rebooting...");
delay(5000);
ESP.restart();
}
// Tu podajemy nazwę naszego nowego projektu (tak będzie widoczny w ArduinoIDE)
ArduinoOTA.setHostname("NowyProjektTestowy");
// Jeżeli chcemy hasło, korzystamy z jednej z poniższych linii
//ArduinoOTA.setPassword("admin");
// ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");
ArduinoOTA
.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH)
type = "sketch";
else // U_SPIFFS
type = "filesystem";
})
.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();
}
void obslugaOTA(){
ArduinoOTA.handle();
}
W powyższym pliku musimy ustawić parametry naszej sieci WiFi oraz nazwę projektu. Nazwa projektu, to dowolna nazwa pod jaką nasz układ będzie widoczny w sieci WiFi przez ArduinoIDE. W sytuacji, gdy chcemy zabezpieczyć nasz układ przed nieautoryzowanym dostępem możemy skorzystać z hasła. Będzie wymagane podczas programowania układu. Hasło możemy podać w sposób jawny lub korzystając z kodowania MD5. Wystarczy odkomentować jedną z instrukcji. Pozostało tylko wykorzystanie OTA we własnym projekcie. Dodajemy do funkcji setup inicjalizację OTA, a do funkcji loop obsługę OTA. Wgrywamy program "normalne" poprzez USB i od tego momentu możemy wgrywać program poprzez sieć WiFi.
void setup() {
beginOTA();
}
void loop() {
obslugaOTA();
}
Jak widać na powyższym przykładzie w miejscu przeznaczonym na właściwy kod naszego projektu mamy porządek. Wystarczyły dwie instrukcje i już mamy załatwione programowanie poprzez sieć, przy okazji nasz układ ma już zaimplementowaną obsługę WiFi, z której można korzystać w kodzie. Poniżej zrzut pokazujący , jak widoczny jest nasz układ w ArduinoIDE.
Podsumowanie
Jak widać na powyższym przykładzie zdalne programowanie jest proste w implementacji, zwłaszcza że cały niezbędny kod mamy gotowy do użycia. Przeniesienie wszystkiego do odrębnego pliku ma jeszcze jedną zaletę - bez problemu możemy skopiować przygotowany plik do kolejnych projektów zmieniając tylko nazwę, pod jaką układy będą widoczne w sieci.