20221110 ArduinoOTA Firmware Updates

Missie:

ESP32 en ESP8266 update per WiFi.

Hoe mooi zou het zijn om een ESP via de WiFi toegang te kunne updaten, m.a.w. een nieuwe of aangepaste sketch te kunnen uploaden?
WiFi is op de ESP aanwezig, dus niks zou ons teken moeten kunnen houden. Toch?

arduinoOTA.jpg

Stap 1 - Bekijk een eerdere post.

Bekijk deze post we gaan dezelfde ESP gebruiken.
En het gaat dan alleen om de manier om verbinding te krijgen, we gaan met een andere sketch aan nde slag.

Stap 2 - OTA project aanleggen.

Ga in de verkenner naar de locatie waar je Arduino projecten staan en maak een map met de naam OTA aan.
In deze map maak je dan een bestand aan met de naam OTA.ino aan.

createFolder.jpg.jpg

Dubbel klik op dit bestand en de Arduino IDE wordt geopend met deze lege sketch.

Stap 3 - OTA library.

Vervolgens ga je op onderzoek of de OTA library geladen is.
Ga boven in de balk naar ToolsManage Libraries om naar de Library Manager te gaan:
In het witte venster typ je OTA in en alles wat met OTA te maken heeft wordt getoond.

OTAlib.jpg.jpg

Scroll omlaag totdat je de bibliotheek <ArduinoOTA> ziet.
Versie 1.0.9 is nu (10 november 2022 om 20:04) de actuele versie.
Druk op de Install toets en wacht tot dit klaar is.
Daarna klik je op Close. In de voorbeelden zou je onder FileExamplesArduinoOTA moeten vinden:

success.jpg

Open dit bestand in een nieuw venster.

BasicOTA.jpg

Stap 3 - OTA sketch opbouw.

We gaan er van uit dat bovenstaand gelukt is, dus gaan we een sketch opbouwen.
Vanuit de BasicOTA.ino sketch gaan we het #include gedeelte overnemen.
Het gedeelte waar de Wifi credentials zijn opgesomd, heb ik een beetje anders opgelost.
In dezelfde directory heb ik een bestand met de naam WiFiCredentials.h opgenomen.
Dit bestand vermeldt het WiFi-SSID en het WiFi wachtwoord op de volgende manier:

						#pragma once
						const char* mySSID = "SSID";
						const char* myPASS = "password";
						
					

Maar dan natuurlijk met de juiste gegevens!

Zo gaat de sketch er uit zien:

						#include <WiFi.h>               // WiFi library for WiFi connection
						#include <ESPmDNS.h>            // Multicast DNS support
						#include <WiFiUdp.h>            // Library for Arduino WiFi shield
						#include <ArduinoOTA.h>         // ArdionoOTA library
						#include "WiFiCredentials.h"    // WiFiCredentials.h is in the same directory 
						                                // and contains SSID and password

						void setup() {
							Serial.begin(115200);
							//--- Boot message
							Serial.println("Booting...");
							//--- Startup WiFi
							WiFi.mode(WIFI_STA);
							WiFi.begin(mySSID, myPASS);
							Serial.print("Connecting to WiFi.");
							while (WiFi.status() != WL_CONNECTED) {
								delay(500);
								Serial.print(".");
							} // while
							Serial.println(" --> is connected");
							//--- ArduinoOTA options:
							// Port defaults to 3232
							// ArduinoOTA.setPort(3232);
							//
							// Hostname defaults to esp3232-[MAC]
							// ArduinoOTA.setHostname("myesp32");
							//
							// No authentication by default
							// ArduinoOTA.setPassword("admin");
							//
							// Password can be set with it's md5 value as well
							// MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
							// ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");
							//
							//--- OTA mechanism starts
							ArduinoOTA.onStart([]() {
								String type;
								if (ArduinoOTA.getCommand() == U_FLASH) {
									type = "sketch";
								} else { // U_SPIFFS
									type = "filesystem";
								} // if else
								// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
								Serial.println("Start updating " + type);
							});// .onStart
							ArduinoOTA.onEnd([]() {
								Serial.println("\nEnd");
							}); // onEnd
							ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
								Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
							}); // onProgress
							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");
							}); // onError
							//--- ArduinoOTA begin
							ArduinoOTA.begin();
							Serial.println("ArduinoOTA setup ready.");
							Serial.print("IP Address :  ");
							Serial.println(WiFi.localIP());
						} // void setup()

						void loop() {
							ArduinoOTA.handle();
							// code comes here
						} // void loop()
						
					

Stap 4 - Versiebeheer met GIT toevoegen.

De verwachting is niet dat alles de eerste keer werkt en ook heb ik zaken in de pipeline om de code te gaan vergemakkelijken.
Daarom gaan we een git repository opbouwen om wijzigingen bij te houden.
Ik doe dit met de commando regel, maar het kan ook met een venster geörienteerd programma:
git extensions.
GIT gaan we hier niet benandelen. Installeer GIT en voer de commando’s uit, of laat GIT weg. Ga met de verkenner naar de map waar je de code hebt neergezet. Met de rechte muisknop krijg je nu een serie mogelijkheden. Klik op Git bash here en een nieuw commando venster wordt geopend.

GitBash.jpg

In dit commando venster voer je achtereenvolgens de volgende opdrachten in.
De eerste opdracht is om GIT te initialiseren.

git init

Dan moeten we de bestanden aan git toevoegen met:

git add .

Dan gaan we de bestanden met git verbinden met:

git commit -m "Initial commit"

Vraag daarna de status op van git met:

git status

Git zal melden dat je op de master branch zit en dat er niks meer te committen valt.
Met het volgende commando kun je de wijzigingen zien.

git log

Download de sketch naar het board, wacht tot dit klaar is.
Daarna het board opnieuw opstarten, nadat het board verbonden is met je Wifi zie je het volgende:

connect.jpg

Stap 5 - OTA download.

Zie ook dat het verbinden met WiFi meer dan een minuut duurde. Geduld is een schone zaak, ook hier.

Een upload naar dit IP adres mondt uit in een foutmelding. Er is nog een programma dat door de firewall wordt tegengehouden. Laat dit programma toe en in de volgende upload heb je succes.

Nu nog de hostname en het IP adres fixen.
Ik wil de hostname SP32testOTA toekennen en een vast IP adres en DNS server.

Voor de hostname gaan we het commentaar teken in regel 26 weghalen en voegen de hostname toe.
In het setup gedeelte wordt deze hostname uitgeprint.

Voor het statisch IP adres moeten we wat meer doen, zie de regels 9 t/m 13 en de regels 22 en 23 van de uiteindelijke code.

Download

Volgens de documentatie zit er een LED op IO2, dat is pin 2.
De sketch breid ik in het setup() gedeelte uit met:

pinMode(2, OUTPUT);

In het loop() gedeelte komen er 4 regels bij:

						digitalWrite(2, HIGH);
						delay(1000);
						digitalWrite(2, LOW);
						delay(1000);
						
					

Ook dit zit in de bovenstaande download.

Nu moet het mogelijk zijn om deze sketch via het WiFi naar de ESP te laden en vervolgens de LED te zien knipperen.
Omdat mijn Arduino omgeving in een VMware draait en ik normaal gesproken de netwerkkaart op NAT heb staan om ook binnen de VMware aan internet te kunnen, met gescheiden netwerken, ga ik onderzoeken hoe ik dat kan regelen.
Nu heb ik binnen VM een 192.168.32.xxx/24 netwerk.
Gewoon naar BRIDGED schakelen lijkt de oplossing. Dan heb ik een 192.168.1.xxx/24 netwerk.
Zie ik nu de download IP poort binnen Arduino IDE? Yesss... ik zie een nieuwe poort:

IPport.jpg

Als een OTA upload niet lukt, of de poort wordt niet zichtbaar, dan controleer de volgende voorwaarden voor een OTA upload:

  1. Installeer de juiste USB drivers (typisch CP2102 en/of CH340g).
  2. De ESP en de PC moeten in hetzelfde netwerk ztaan (doe een PING om dit te controleren.
  3. Installeer Apple Bonjour voor Windows, als je met Windows werkt.
  4. Herstart de Arduino IDE.
  5. ESP.restart() werkt niet na een firmware update over USB.
    Herstart het ESP bord handmatig en het werkt weer.
  6. Ben er zeker van dat de ESP tools in de Arduino IDE zijn toegevoegd.

Nu is het jammer dat je voor een herstart na de OTA upload de ESP nog opnieuw moet opstarten.
M.a.w. ik moet nog altijd de voedingsspanning van de ESP gaan onderbreken.
Dat gooit het gunstige effect van een OTA upload ondersteboven.
Ook dat gaan we oplossen.

Om dit te bereiken gaan we een webserver op de ESP installeren.
Deze webserver kunnen we vervolgens in onze webbrowser starten en er een opdracht aan meegeven.
De twee opdrachten die we gaan laten gebeuren zijn restartOTA om de sketch helemaal opnieuw te starten.
En SetOTAflag om het OTA mechanisme op te starten. Hierbij wordt de sketch niet opnieuw opgestart.
Ook is er nog iets toegevoegd om te zien dat het programma inderdaad iets doet, behalve het knipperen.
De complete code is hier beneden te downloaden.

Download

Stap 6 - De code comprimeren.

Het gedeelte waar het OTA mechanisme wordt gedefinieerd (de regels 40 t/m 95 in bovenstaande sketch) zal in het algemeen niet wijzigen. Stel we maken van dit gedeelte een apart bestand met de naam OTAsetup.h en verplaatsen dat bestand naar het library gedeelte.
De code wordt daardoor een stuk overzichtelijker.
Het .ino gedeelte en het .h gedeelte is hier beneden apart te downloaden.

OTA.ino OTAsetup.h
Download Download

Stap 7 - Debuggen.

Dan hebben we nog een opgave: nl. debug informatie naar buiten sturen.
Dat kan op veel verschillende manieren en er zijn heel mooie bibliotheken voor.
Tevens zie ik graag dat ik deze debug informatie kan aan- en uitschakelen.
Ik ga het zo simpel mogelijk houden met #define.
Bovenin het #define gedeelte komt het volgende:

						#define DEBUG 1
						
#if DEBUG == 1 #define debug(x) Serial.print(x) #define debugln(x) Serial.println(x) #else #define debug(x) #define debugln(x) #endif

Wat staat daar nou?

Eeste definiëren we een variabel genaamd DEBUG en deze variabele kunnen we aanzetten met "1" en uitzetten met "0". Nu staat hij aan.
Daarna gaan we in een if...then...else kijken of hij aan of uit staat.
Staat hij aan, dan vervangen we debug(x) door Serial.print(x) en vervangen we debugln(x) door Serial.println(x).
Nou ja... we..., wij vervangen niks, de compiler vervangt.
En als DEBUG uitstaat vervangen we debug(x) en debugln(x) door... niks.
Daarmee slaat de compiler deze regels over en maakt de gecompileerde code kleiner.
Die informatie heb je na het debuggen immers niet meer nodig, sterker nog, hij vertaagt de afloop van het programma.
Controleer dat maar, de code zal ca. 75 bytes korte zijn als DEBUG uit staat.

Wat wij moeten vervangen is het volgende:
Overal waar Serial.print(x) of Serial.println(x) in de code staat, t.b.v. debugging, gaan we dat vervangen door debug(x) of debugln(x). Dus:

						debug("Loop : ");
						debug(millis());
						debugln(" milli seconds.");
						
					

Het bestand kun je hier beneden downloaden.

Download

Stap 8 - Debuggen via het netwerk.

Nu nog een klein stapje:
Als we al via het WiFi aan onze ESP kunnen, moet die debug informatie toch ook via WiFi komen.?!
Hiervoor gaan we de TelnetStream bibliotheek gebruiken.
Als je op de link klikt ga je meteen naar GitHub, waar je de code als .ZIP bestand kunt downloaden en daarna met de library manager van de Arduino IDE kunt integreren.
Maar het kan ook met ToolsManage Libraries en dan TelnetStream in het witte venstertje invoeren.
En daar verschijnt al TelnetStream van Juraj Andrassy. Klik op Install en wacht tot het klaar is.
Sluit de IDE af en start hem opnieuw op, om de library te laden.
In het #include gedeelte van de code neem je het header bestand van TelnetStream op.

						#include <TelnetStream.h>
						
					

In het DEBUG gedeelte gaan we de Serial.print(x) en Serial.println(x) vervangen door TelnetStream.print(x) en TelnetStream.println(x).
Dus:

						#define DEBUG 1
						
#if DEBUG == 1 #define debug(x) TelnetStream.print(x) #define debugln(x) TelnetStream.println(x) #else #define debug(x) #define debugln(x) #endif

Tevens zetten we DEBUG weer op "1".

LET OP: Juraj Andrassy heeft blijkbaar geen KEYWORD bestand aangemaakt, niks kleurt.

In het setup() gedeelte van de code moeten we nog een TelnetStream.begin(); toevoegen.
Stuur dit bestand naar je ESP.

Download

Hoe gaan we deze informatie "uit de lucht" halen. We gaan PuTTY opstarten.
In het adres venster geven we het IP adres van de ESP in, in in het port 23 en het type schakelen we naar Telnet.

PuTTYsetup.jpg

Druk op Open en in het volgende venster komen netjes de debug meldingen langs.

TelnetDebug.jpg
Back to top