Ο μικροελεκτής ESP32 έχει τη δυνατότητα να δημιουργήσει wifi δίκτυο με δύο τρόπους, είτε φτιάχνοντας ένα Access Point (AP) όπου λειτουργεί σαν Wi-Fi hotspot (router) είτε φτιάχνοντας ένα Station (STA) όπου λειτουργεί σαν πελάτης (client).
Η δημιουργία του Access Point χρησιμοποιείτε συνήθως για να μπορέσει να συνδεθεί ένα κινητό τηλέφωνο ή ο browser ενός υπολογιστή με τη συσκευή που έχει τον ESP32. Στο κινητό ή στον υπολογιστή πρέπει να ψάξουμε τα διαθέσιμα wifi και να συνδεθούμε σε αυτό της συσκευής ESP32. Συνήθως όταν λειτουργεί σαν Access Point παίρνει by default ip address 192.168.4.1 Μέσα από αυτή τη σύνδεση παρέχονται στη συσκευή του ESP32 διάφοροι παράμετροι όπως ssid, password, ή ότι άλλο θεωρείται κρίσιμο στοιχείο για να ξεκινήσει να λειτουργεί αυτόνομα. Όταν η συσκευή λειτουργεί σε Access Point Mode δεν συνδέεται με το internet.
Στην περίπτωση που ο ESP32 λειτουργεί σε Station Mode (STA) δηλαδή σαν πελάτης client, τότε συνδέεται σε ένα υπάρχον wi-fi, παίρνει ip address από το router και μπορεί να έχει πρόσβαση στο internet ή σε άλλες συσκευές.
Υπάρχει και ο σύνθετος τρόπος σύνδεσης STA + AP που χρησιμοποιείται σπάνια και για περιπτώσεις debugging .
Μικροελεγκτές όπως το ESP32 χρησιμοποιούν NVS (Non-Volatile Storage), όπου μπορούν να αποθηκευτούν δεδομένα όπως για παράδειγμα ρυθμίσεις, αριθμοί ή strings που δεν χάνονται όταν κλείνει η συσκευή. Συνήθως χρησιμοποιείται η βιβλιοθήκη “Preferences.h” για να υλοποιηθεί αυτή η λειτουργία.
Μια έκφραση της παρακάτω μορφής χρησιμοποιείται για την ανάκτηση των αποθηκευμένων τιμών ssid και passs που βρίσκονται στην περιοχή που έχουμε ονοματίσει wifi. Το true σημαίνει ότι η περιοχή έχει ανοίξει μόνο για διάβασμα.
prefs.begin("wifi", true);
savedSSID = prefs.getString("ssid", "");
savedPASS = prefs.getString("pass", "");
prefs.end();
Αντίστοιχα μια έκφραση της παρακάτω μορφής χρησιμοποιείται για την αποθήκευση των τιμών ssid και passs στην περιοχή που ορίζουμε με το όνομα wifi. Το false στην begin σημαίνει ότι η περιοχή έχει ανοίξει για γράψιμο και διάβασμα.
prefs.begin("wifi", false);
prefs.putString("ssid", ssid);
prefs.putString("pass", pass);
prefs.end();
Στο παράδειγμα επέλεξα τη δημιουργία ενός WebServer με τον ESP32 για να δείξω πως με όλες τις λειτουργίες που ανέπτυξα παραπάνω μπορώ να εξασφαλίσω ένα αυτόματο wifi setup. Έτσι κάθε φορά που η συσκευή μου αλλάζει τόπο εγκατάστασης μπορώ απλά να τη συνδέω στο νέο wifi δίκτυο. Εξάλλου αυτό είναι ένα τμήμα από την αναβάθμιση του “ESP32 WebServer” δηλαδή του μετεωρολογικού σταθμού, που σας παρουσιάζω στο σχετικό άρθρο.
Στον κώδικα που ακολουθεί βλέπουμε ότι το setup προσπαθεί να ανακτήσει ssid και pass από την περιοχή της Non-Volatile μνήμης με το όνομα wifi. Αν αυτά τα στοιχεία υπάρχουν τότε καλεί connectToWiFi() και προχωρά στην σύνδεση με το wifi. Αν αυτά τα στοιχεία δεν υπάρχουν (ή δεν είναι σωστά, αυτό θα το δείτε στην connectToWiFi) τότε καλεί την startAP() η οποία βάζει τη συσκευή σε Access Point Mode (AP) προκειμένου να αναζητήσει και να αποθηκεύσει τα απαραίτητα στοιχεία.
Οι πρώτες εντολές της startAP() είναι η WiFi.mode(WIFI_AP) που ενεργοποιεί τη λειτουργίας σε AP και η WiFi.softAP(“ESP32_Setup”, “12345678”); που δίνει το όνομα “ESP32_Setup” στο wifi και ορίζει password το “12345678”.
Η startAP() αφού ολοκληρώσει το έργο της καλεί την ESP.restart() η οποία κάνει restart τον ESP32. Αυτή τη φορά, και εφόσον τα στοιχεία που αποθηκεύσαμε είναι σωστά, θα κληθεί η connectToWiFi() για να συνδέσει τη συσκευή με το wifi του router που επιθυμούμε. Παρατηρούμε ότι η connectToWiFi() αφού δώσει ip address στη συσκευή τελειώνει με την κλήση της startServer(). Η startServer() βάζει σε λειτουργία το web server, στην περίπτωση του παραδείγματος η κλήση στο server γίνεται στη διεύθυνση http://ipaddress/hello και η απάντηση από το server είναι “Hello from ESP32 .-”
Το πρόγραμμα που διαβάζετε παρακάτω μπορείτε να το κατεβάσετε από εδώ
#include <WiFi.h>
#include <WebServer.h>
#include <Preferences.h>
WebServer server(80);
Preferences prefs;
String savedSSID;
String savedPASS;
bool wifiConnected = false;
// ================== SETUP ==================
void setup() {
Serial.begin(115200);
delay(1000);
prefs.begin("wifi", true);
savedSSID = prefs.getString("ssid", "");
savedPASS = prefs.getString("pass", "");
prefs.end();
if (savedSSID != "") {
connectToWiFi();
} else {
startAP();
}
}
// ================== LOOP ==================
void loop() {
server.handleClient();
}
// ================== CONNECT TO WIFI ==================
void connectToWiFi() {
Serial.println("Connecting to saved WiFi...");
WiFi.mode(WIFI_STA);
WiFi.begin(savedSSID.c_str(), savedPASS.c_str());
int timeout = 20;
while (WiFi.status() != WL_CONNECTED && timeout-- > 0) {
delay(500);
Serial.print(".");
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\nConnected!");
Serial.print("IP: ");
Serial.println(WiFi.localIP());
wifiConnected = true;
startServer();
} else {
Serial.println("\nFailed. Starting AP...");
startAP();
}
}
// ================== START AP ==================
void startAP() {
WiFi.mode(WIFI_AP);
WiFi.softAP("ESP32_Setup", "12345678");
Serial.print("AP IP: ");
Serial.println(WiFi.softAPIP());
// ROOT
server.on("/", []() {
String page = "<h2>WiFi Setup</h2>";
page += "<a href='/scan'>Scan WiFi</a>";
server.send(200, "text/html", page);
});
// SCAN
server.on("/scan", []() {
int n = WiFi.scanNetworks();
String page = "<h3>Select WiFi</h3>";
for (int i = 0; i < n; i++) {
String ssid = WiFi.SSID(i);
page += "<a href='/set?ssid=" + ssid + "'>" + ssid + "</a><br>";
}
server.send(200, "text/html", page);
});
// SET PASSWORD
server.on("/set", []() {
String ssid = server.arg("ssid");
String page = "<h3>" + ssid + "</h3>";
page += "<form action='/save'>";
page += "<input type='hidden' name='ssid' value='" + ssid + "'>";
page += "Password:<br>";
page += "<input type='password' name='pass'><br><br>";
page += "<input type='submit' value='Connect'>";
page += "</form>";
server.send(200, "text/html", page);
});
// SAVE + CONNECT
server.on("/save", []() {
String ssid = server.arg("ssid");
String pass = server.arg("pass");
prefs.begin("wifi", false);
prefs.putString("ssid", ssid);
prefs.putString("pass", pass);
prefs.end();
server.send(200, "text/html", "<h3>Saved. Rebooting...</h3>");
delay(1000);
ESP.restart();
});
server.begin();
}
// ================== NORMAL SERVER ==================
void startServer() {
// Test endpoint
server.on("/", []() {
server.send(200, "text/plain", "ESP32 is running");
});
server.on("/hello", []() {
server.send(200, "text/plain", "Hello from ESP32 .-" );
});
server.begin();
}