[ 225 keer bekeken / views ]
Iedereen die weleens een programma schrijft, maakt gebruik van bibliotheken en klassen (classes) om zijn software te ontwikkelen. Als je (in C of C++) een programma schrijft voor een Arduino- of Espressif-bordje, voeg je dergelijke bibliotheken toe met het #include <..>
-statement. Deze bibliotheken fungeren vaak als black boxes waarvan je de interne werking niet hoeft te kennen of te begrijpen.
Ik werk veel met Espressif-bordjes (ESP8266 en ESP32), omdat deze veel mogelijkheden bieden. Je kunt er eenvoudig een WiFi-verbinding mee maken (met de WiFi- of WiFiManager-bibliotheek). Met behulp van een ingebouwde WebServer (ook een standaardbibliotheek) kan ik het ontwikkelde programma ‘besturen’ en configureren. Daar heb je dan wel de nodige HTML, stylesheets en JavaScript bij nodig. Daarnaast is het bijna altijd handig om de juiste tijd via het Network Time Protocol (NTP) op te halen. Ook vind ik het prettig om mijn projecten te debuggen via het telnet-protocol, zodat ik met een tekstgebaseerde terminal verbinding met zo’n project kan maken. Hiervoor is de bibliotheek TelnetStream mijn favoriete keuze. De Espressif-bordjes bieden bovendien de mogelijkheid om een deel van het geheugen als opslag te gebruiken (als een soort harde-schijf). Wil je hiervan gebruik maken, dan is een systeem voor het beheren van deze opslag erg prettig. Hiervoor heb ik eerder al code ontwikkeld (géén bibliotheek omdat ik toen nog niet wist hoe dat moet) onder de naam FSmanager en FSexplorer.
Al met al gebruik ik een behoorlijk aantal bibliotheken, die samen toch nog aardig wat code vereisen om deze bibliotheken optimaal in te zetten.
En zoals altijd dacht ik: “Dit moet eenvoudiger kunnen”.
Daarom ben ik begonnen met het ontwikkelen van drie bibliotheken die al het bovenstaande met eenvoudige stukjes code regelen. In drie posts zal ik deze bibliotheken en hun gebruik beschrijven:
- Deel 1: Networking
- Deel 2: Single Page Application (de GUI)
- Deel 3: Filesystem Manager
Dit is deel 1 en gaat dus over Networking.
Networking
Deze bibliotheek maakt het eenvoudig om je project met je WiFi modem (Access Point) te verbinden. Ben je eenmaal verbonden met WiFi dan maakt deze bibliotheek het mogelijk om nieuwe versies van je programma’s Over The Air (OTA) te flashen. Geen kabels meer nodig! Ook zal deze bibliotheek ervoor zorgen dat je je project niet alleen via het IP-adres kunt benaderen maar óók via een opgegeven hostname (bijvoorbeeld “project.local”). Debug uitvoer kun je zowel via de seriële poort bekijken maar ook via telnet. Tenslotte heb je, zonder er iets extra’s voor te hoeven doen, ook de actuele (atoom) tijd tot je beschikking.
Installatie PlatformIO
Werk je met VSCode/PlatformIO dan hoef je alleen de link naar de repo in je platformio.ini bestand op te nemen:
lib_deps = https://github.com/mrWheel/esp-networking
Installatie Arduino IDE
Voor de Arduino IDE moet je de repo als “.zip” bestand downloaden.

Het esp-networking-main.zip
bestand moet je ergens op je computer bewaren.

Start nu de Arduino IDE op en klik op [Sketch] en selecteer [Add .ZIP library…]

Nu navigeer je naar de folder waar je het esp-networking-main.zip
bestand eerder hebt opgeslagen ..

… en klik je op [Choose].
Installeer nu ook de volgende bibliotheken (als dat nog niet gebeurd is):
- WiFiManager
- ESP8266WiFi (voor esp8266) of WiFi (voor esp32)
- ESP8266mDNS (voor esp8266) of ESPmDNS (voor esp32)
- ArduinoOTA
De bibliotheek is nu klaar om gebruikt te worden.
Eenvoudig gebruik (basic)
#include "Networking.h" Networking* network = nullptr; Stream* debug = nullptr; void setup() { network = new Networking(); //-- Parameters: hostname, resetWiFi pin, serial object, baud rate debug = network->begin("my-esp", 0, Serial, 115200); if (!debug) { //-- Restart if connection fails ESP.restart(); } } void loop() { //-- Must be called in main loop network->loop(); //-- Use debug stream for output debug->println("Hello World"); }
Uitleg
In regel 1 vertellen we de compiler dat we de “Networking” bibliotheek gaan gebruiken.
Regel 3 zorgt dat we een pointer creëren naar het Networking object.
Regel 4 maakt een pointer “debug” aan van het type Stream.
In regel 8 maken we een nieuw object “netwerk” aan van de klasse Networking.
Regel 10 is waar het allemaal om draait. We roepen de methode “begin()” aan met een aantal parameters.
- De eerste is de hostnaam, in dit geval “esp8266”
- De tweede is het nummer van een GPIO pin (in dit geval “0”). Als tijdens het opstarten deze GPIO pin “Laag” wordt gemaakt worden de WiFi credentials verwijderd en start het WiFi Manager portal op.
- De derde parameter geeft aan op welk seriële poort debug uitvoer wordt geschreven (naast de uitvoer naar de telnet client).
- De vierde parameter geeft de snelheid aan waarmee naar de seriële poort moet worden geschreven.
- Er is ook nog een vijfde parameter maar die heeft standaard de waarde null.
In de loop() functie moet de network->loop() functie worden aangeroepen om alles naar behoren te laten werken.
WiFi Configuratie
Eerste Opstart:
- Het apparaat maakt een Access Point aan met de naam van de
hostnaam
. - Maak verbinding met dit AP via je telefoon/computer.
- Configureer je WiFi-instellingen via het captive portal.
WiFi Instellingen Reset:
- Houd de
resetWiFiPin
laag tijdens de opstart. - WiFi-instellingen worden gewist.
- Het apparaat gaat terug naar de AP-modus voor herconfiguratie.
Remote Debugging
Verbinden via Telnet:
telnet apparaat-ip-adres
Standaard poort: 23
Verbinden via netcat (nc):
nc apparaat-ip-adres 23
Of gebruik in plaats van apparaat-ip-adres
de mDNS-naam hostnaam.local.
Kenmerken:
- Alle debug-uitvoer wordt zowel naar de seriële poort als naar Telnet geprint.
- Slechts één telnet-sessies wordt ondersteund (gelijktijdig).
- Automatisch sessiebeheer.
Uitgebreid Gebruik van OTA en WiFiManager
De bibliotheek biedt callbackfuncties voor OTA (Over-The-Air) update-evenementen en WiFiManager portal-activatie, waarmee je aangepaste code kunt uitvoeren op specifieke momenten:
void setup() { network = new Networking(); debug = network->begin("my-esp", 0, Serial, 115200); //-- Registreer OTA callbacks network->doAtStartOTA([]() { //-- Aangeroepen wanneer de OTA-update begint digitalWrite(LED_BUILTIN, LOW); //-- Zet LED aan debug->println("OTA-update begint..."); }); network->doAtProgressOTA([]() { //-- Aangeroepen bij elke 20% voortgang digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); //-- Wissel LED debug->println("OTA: Nog eens 20% voltooid"); }); network->doAtEndOTA([]() { //-- Aangeroepen wanneer de OTA-update bijna eindigt digitalWrite(LED_BUILTIN, HIGH); //-- Zet LED uit debug->println("OTA-update eindigt..."); }); //-- Registreer WiFiManager callback network->doAtWiFiPortalStart([]() { //-- Aangeroepen wanneer het WiFiManager portal is gestart (geen geldig SSID gevonden) digitalWrite(LED_BUILTIN, LOW); //-- Zet LED aan debug->println("WiFi-configuratie portal gestart"); }); }
Met deze callbacks kun je:
- Het apparaat voorbereiden wanneer een update start (bijvoorbeeld kritieke gegevens opslaan, lopende processen stoppen).
- De voortgang monitoren bij 20%-intervallen (bijvoorbeeld een display bijwerken, indicatoren wisselen).
- Opruimoperaties uitvoeren voordat de update wordt afgerond.
- Visuele feedback geven tijdens updates met LED’s of displays.
- Update-voortgang loggen naar externe systemen of opslag.
Netwerkstatus
if (network->isConnected()) { debug->print("IP Adres: "); debug->println(network->getIPAddressString()); }
NTP Tijdbeheer
De bibliotheek biedt uitgebreide NTP (Network Time Protocol) functionaliteit met automatische synchronisatie:
void setup() { network = new Networking(); debug = network->begin("my-esp", 0, Serial, 115200); //-- Start NTP met Amsterdam tijdzone if (network->ntpStart("CET-1CEST,M3.5.0,M10.5.0/3")) { debug->println("NTP succesvol gestart"); } //-- Optioneel: Gebruik aangepaste NTP-servers const char* ntpServers[] = {"time.google.com", "time.cloudflare.com", nullptr}; network->ntpStart("CET-1CEST,M3.5.0,M10.5.0/3", ntpServers); } void loop() { network->loop(); //-- Verzorgt automatische NTP-synchronisatie elk uur if (network->ntpIsValid()) { debug->print("Huidige tijd: "); debug->println(network->ntpGetDateTime()); } }
Kenmerken:
- Automatische synchronisatie elk uur.
- Ondersteuning voor tijdzones met POSIX tijdzone strings.
- Ondersteuning voor aangepaste NTP-servers.
- Tijdzone-wijzigingen zonder de standaardinstellingen te beïnvloeden.
- Diverse tijdformaten (epoch, datum, tijd, datetime).
Tijdzones
Tijdzones worden gespecificeerd met POSIX tijdzone strings. Veelgebruikte voorbeelden:
- Centrale Europese Tijd: “CET-1CEST,M3.5.0,M10.5.0/3”
- Oostelijke Tijd: “EST5EDT,M3.2.0,M11.1.0”
- UTC: “UTC0”
- Japan: “JST-9”
Als je mij wil helpen om meer van dit soort posts te schrijven, overweeg dan om een kleine donatie te geven door op de knop hieronder te klikken.
Voorbeelden
Alle in deze post gepresenteerde code kun je vinden in de examples
folder van de github repository.
ESP Networking Library API Documentation
Wat is een API?
Een API (Application Programming Interface) is een set van duidelijk gedefinieerde methoden, functies en protocollen die ontwikkelaars kunnen gebruiken om met een bepaalde software of hardware te communiceren. Een API fungeert als een brug tussen verschillende softwarecomponenten, waardoor ze met elkaar kunnen communiceren zonder dat de ontwikkelaar de interne werking van elke component hoeft te begrijpen.
In de context van deze bibliotheek biedt de API een eenvoudige manier om netwerkfunctionaliteit te implementeren in ESP8266/ESP32 projecten, zonder dat u zich zorgen hoeft te maken over de complexe details van WiFi-verbindingen, OTA-updates, telnet-servers of NTP-tijdsynchronisatie.
Networking Library Overzicht
De ESP Networking bibliotheek biedt een uitgebreide set functies voor het beheren van netwerkverbindingen op ESP8266 en ESP32 microcontrollers. De bibliotheek vereenvoudigt het proces van:
- WiFi-verbinding en -configuratie
- Over-the-Air (OTA) firmware updates
- Telnet server voor externe debugging
- mDNS service discovery
- NTP tijdsynchronisatie
- Automatische WiFi-herverbinding
Hoofdklassen
Networking Klasse
De Networking
klasse is de primaire interface voor alle netwerkfunctionaliteit.
Initialisatie
Networking* network = new Networking(); Stream* debug = network->begin("my-esp", 0, Serial, 115200); //-- Optioneel: callback voor WiFi portal network->doAtWiFiPortalStart([]() { Serial.println("WiFi configuratie portal gestart"); });
Belangrijke Methoden
begin(hostname, resetWiFiPin, serial, serialSpeed, wifiCallback)
Initialiseert de netwerkfunctionaliteit.
hostname
: De naam waarmee het apparaat op het netwerk zichtbaar isresetWiFiPin
: GPIO-pin die gebruikt wordt om WiFi-instellingen te resetten (verbind met GND om te resetten)serial
: HardwareSerial object voor debug outputserialSpeed
: Baudrate voor seriële communicatiewifiCallback
: Optionele callback functie die wordt aangeroepen wanneer de WiFi-configuratieportal start
//-- Voorbeeld: Initialisatie met callback voor WiFi portal Stream* debug = network->begin("my-esp", 0, Serial, 115200, []() { Serial.println("WiFi configuratie portal gestart!"); //-- Hier kunt u bijvoorbeeld een LED laten knipperen });
loop()
Moet regelmatig worden aangeroepen in de hoofdlus van uw programma om netwerkgebeurtenissen af te handelen.
void loop() { network->loop(); //-- Verplicht voor correcte werking //-- Uw eigen code hier }
WiFi-gerelateerde methoden
//-- Controleer of WiFi verbonden is if (network->isConnected()) { Serial.println("Verbonden met WiFi"); } //-- Verkrijg het IP-adres als IPAddress object IPAddress ip = network->getIPAddress(); //-- Verkrijg het IP-adres als string String ipStr = network->getIPAddressString(); Serial.print("IP-adres: "); Serial.println(ipStr); //-- Bijvoorbeeld: "192.168.1.105" //-- Handmatig opnieuw verbinden met WiFi (indien nodig) network->reconnectWiFi();
OTA Update Callbacks
//-- Registreer callbacks voor OTA-updates network->doAtStartOTA([]() { Serial.println("OTA update gestart"); //-- Bijvoorbeeld: schakel LED in om aan te geven dat update bezig is }); network->doAtProgressOTA([]() { Serial.println("OTA update voortgang"); //-- Wordt ongeveer elke 20% aangeroepen }); network->doAtEndOTA([]() { Serial.println("OTA update voltooid"); //-- Bijvoorbeeld: schakel LED uit });
NTP Tijdsynchronisatie
//-- Start NTP met tijdzone voor Amsterdam if (network->ntpStart("CET-1CEST,M3.5.0,M10.5.0/3")) { Serial.println("NTP succesvol gestart"); } //-- Optioneel: aangepaste NTP-servers opgeven // const char* ntpServers[] = {"time.google.com", "time.cloudflare.com", nullptr}; // network->ntpStart("CET-1CEST,M3.5.0,M10.5.0/3", ntpServers); //-- Controleer of NTP tijd geldig is if (network->ntpIsValid()) { Serial.println("NTP tijd is geldig"); } //-- Verkrijg huidige datum (YYYY-MM-DD) Serial.print("Datum: "); Serial.println(network->ntpGetDate()); //-- Bijvoorbeeld: "2025-03-15" //-- Verkrijg huidige tijd (HH:MM:SS) Serial.print("Tijd: "); Serial.println(network->ntpGetTime()); //-- Bijvoorbeeld: "14:30:25" //-- Verkrijg huidige datum en tijd (YYYY-MM-DD HH:MM:SS) Serial.print("Datum en tijd: "); Serial.println(network->ntpGetDateTime()); //-- Bijvoorbeeld: "2025-03-15 14:30:25" //-- Verkrijg epoch tijd (seconden sinds 1-1-1970) time_t epoch = network->ntpGetEpoch(); Serial.print("Epoch: "); Serial.println(epoch); //-- Bijvoorbeeld: "1742265025" //-- Verkrijg tijd in andere tijdzone (bijvoorbeeld New York) Serial.print("New York tijd: "); Serial.println(network->ntpGetDateTime("EST5EDT,M3.2.0,M11.1.0")); //-- Verkrijg gedetailleerde tijdinformatie als tm struct struct tm timeInfo = network->ntpGetTmStruct(); Serial.printf("Jaar: %d\n", timeInfo.tm_year + 1900); Serial.printf("Maand: %d\n", timeInfo.tm_mon + 1); Serial.printf("Dag: %d\n", timeInfo.tm_mday); Serial.printf("Uur: %d\n", timeInfo.tm_hour); Serial.printf("Minuut: %d\n", timeInfo.tm_min); Serial.printf("Seconde: %d\n", timeInfo.tm_sec);
MultiStream Klasse
De MultiStream
klasse wordt intern gebruikt om output naar zowel de seriële poort als telnet clients te sturen. U hoeft deze klasse normaal gesproken niet direct te gebruiken, maar u kunt het Stream*
object dat door begin()
wordt geretourneerd gebruiken voor alle debug output.
//-- Gebruik het debug object voor alle output debug->println("Deze tekst verschijnt zowel op de seriële monitor als via telnet"); debug->printf("Geformatteerde output: %d, %s\n", 42, "tekst");
Volledige Voorbeelden
Basis Voorbeeld
#include "Networking.h" Networking* network = nullptr; Stream* debug = nullptr; void setup() { Serial.begin(115200); delay(1000); //-- Initialiseer networki network = new Networking(); debug = network->begin("my-esp", 0, Serial, 115200); if (!debug) { ESP.restart(); //-- Herstart als verbinding mislukt } debug->println("Netwerk geïnitialiseerd!"); debug->print("IP-adres: "); debug->println(network->getIPAddressString()); } void loop() { //-- Verplicht: verwerk netwerkgebeurtenissen network->loop(); //-- Uw code hier static unsigned long lastTime = 0; if (millis() - lastTime > 10000) { lastTime = millis(); debug->println("Hallo wereld!"); } }
NTP Voorbeeld
#include "Networking.h" Networking* network = nullptr; Stream* debug = nullptr; void setup() { Serial.begin(115200); delay(1000); //-- Initialiseer network network = new Networking(); debug = network->begin("my-esp", 0, Serial, 115200); if (!debug) { ESP.restart(); } //-- Start NTP met Amsterdam tijdzone if (network->ntpStart("CET-1CEST,M3.5.0,M10.5.0/3")) { debug->println("NTP gestart"); } } void loop() { network->loop(); //-- Toon tijd elke 5 seconden static unsigned long lastTime = 0; if (millis() - lastTime > 5000) { lastTime = millis(); if (network->ntpIsValid()) { debug->print("Huidige tijd: "); debug->println(network->ntpGetDateTime()); } else { debug->println("Wachten op geldige tijd..."); } } }
OTA Update Voorbeeld
#include "Networking.h" Networking* network = nullptr; Stream* debug = nullptr; bool updateInProgress = false; void setup() { Serial.begin(115200); delay(1000); //-- Initialiseer network network = new Networking(); //-- Registreer OTA callbacks network->doAtStartOTA([]() { updateInProgress = true; digitalWrite(LED_BUILTIN, HIGH); //-- LED aan tijdens update }); network->doAtEndOTA([]() { updateInProgress = false; digitalWrite(LED_BUILTIN, LOW); //-- LED uit na update }); //-- Start network debug = network->begin("my-esp", 0, Serial, 115200); if (!debug) { ESP.restart(); } pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, LOW); debug->println("Klaar voor OTA updates!"); debug->print("IP-adres: "); debug->println(network->getIPAddressString()); } void loop() { network->loop(); //-- Normale werking wanneer geen update bezig is if (!updateInProgress) { //-- Uw code hier delay(1000); debug->println("Systeem draait normaal..."); } }
Geavanceerde Functies
WiFi Reset
De bibliotheek ondersteunt het resetten van WiFi-instellingen door een GPIO-pin laag te maken (verbinden met GND). Dit is handig als u uw apparaat naar een ander netwerk wilt verplaatsen.
//-- Bij initialisatie, geef de reset pin op (hier GPIO 0) debug = network->begin("my-esp", 0, Serial, 115200); //-- Als GPIO 0 laag is tijdens opstarten, worden WiFi-instellingen gewist //-- en start de configuratie portal
Telnet Server
De bibliotheek start automatisch een telnet server op poort 23. U kunt verbinding maken met het apparaat via telnet om debug output te zien en te monitoren zonder fysieke verbinding.
$ telnet my-esp.local Verbonden met my-esp.local. Escape character is '^]'. Welcome to [my-esp] Telnet Server!
mDNS Service Discovery
Het apparaat is vindbaar op het lokale netwerk via mDNS met de hostname die u opgeeft, gevolgd door “.local”. Bijvoorbeeld: “my-esp.local”.
Tijdzone Formaten
Voor NTP-tijdsynchronisatie gebruikt de bibliotheek POSIX tijdzone strings. Hier zijn enkele voorbeelden:
- Amsterdam/Nederland:
"CET-1CEST,M3.5.0,M10.5.0/3"
- Londen/UK:
"GMT0BST,M3.5.0/1,M10.5.0"
- New York/US Eastern:
"EST5EDT,M3.2.0,M11.1.0"
- Los Angeles/US Pacific:
"PST8PDT,M3.2.0,M11.1.0"
- Tokyo/Japan:
"JST-9"
- Sydney/Australia:
"AEST-10AEDT,M10.1.0,M4.1.0/3"
Foutafhandeling en Betrouwbaarheid
De bibliotheek bevat ingebouwde mechanismen voor het automatisch opnieuw verbinden met WiFi bij verbindingsverlies. Als het maximale aantal herverbindingspogingen (standaard 5) wordt bereikt, zal het bordje herstarten.
//-- Controleer periodiek de verbindingsstatus if (!network->isConnected()) { debug->println("WiFi-verbinding verloren!"); //-- De bibliotheek zal automatisch proberen opnieuw verbinding te maken //-- U kunt ook handmatig herverbinden: network->reconnectWiFi(); }
Compatibiliteit
De bibliotheek werkt met zowel ESP8266 als ESP32 platforms. Het biedt een consistente API over beide platforms, waardoor uw code gemakkelijk overdraagbaar is.
Licensie
This project is licensed under the MIT License – see the LICENSE file for details.