Eigenes Captive Portal mit dem ESP 8266 (Teil 1) - AZ-Delivery

Hallo en welkom op een speciale blog:

 

Tegenwoordig zou het geen voltooid project moeten zijn, maar eerder een hulpmiddel voor veel van uw eigen projecten met betrekking tot WLAN-toegangsgegevens en ESP8266. Vaak is er het probleem met eigen projecten dat WLAN-toegangsgegevens permanent in hun eigen code zijn geprogrammeerd, maar niet langer kunnen worden gewijzigd of de ESP zijn WLAN-toegangsgegevens "vergeet" zodra een herstart plaatsvindt. Beide zijn problematisch voor een zekere flexibiliteit in de configuratie. De oplossing hiervoor is om de WLAN-toegangsgegevens op te slaan in de interne EEPROM en ervoor te zorgen dat deze op elk moment kunnen worden gewijzigd, zelfs tijdens de firmware-runtime.

Om dit te doen, installeert de ESP met onze captive portal-code in de eerste stap Captive portal  op, een WLAN met de naam "My_WLANDevice" en het wachtwoord "12345678". Hiermee kunnen we verbinding maken met onze mobiele telefoon en vervolgens automatisch van de mobiele telefoon naar de Captive Portal-website worden geleid. Het ziet er zo uit:

 

Captive portal

 

Hierop kunnen we nu klikken op de systeemlink "WiFi-instellingen", en nu komen we op een uitgebreide WiFi-configuratiepagina, waarmee we nu beide een netwerk kunnen selecteren waarmee de ESP verbinding moet maken:

 

Captive Portal - WiFi-installaties

 

Het hier geselecteerde radionetwerk en het ingevoerde wachtwoord worden opgeslagen in de EEPROM. Bij de volgende keer opstarten probeert de ESP verbinding te maken met dit netwerk. Als de poging mislukt omdat het netwerk bijvoorbeeld niet langer toegankelijk is of het wachtwoord is gewijzigd, schakelt de ESP terug naar de toegangspuntmodus en wacht op een nieuwe configuratie.

De code voor de Captive Portal is:

 

 

# opnemen <ESP8266WiFi.h>
# opnemen <WiFiClient.h>
# opnemen <ESP8266WebServer.h>
# opnemen <ESP8266mDNS.h>
# opnemen <DNS-server.h>
# opnemen <EEPROM.h>

statisch const byte WiFiPwdLen = 25;
statisch const byte APSTANAMELEN = 20;

statisch const uint8_t D0   = 16;
statisch const uint8_t D1   = 5;
statisch const uint8_t D2   = 4;
statisch const uint8_t D3   = 0;
statisch const uint8_t D4   = 2;
statisch const uint8_t D5   = 14;
statisch const uint8_t D6   = 12;
statisch const uint8_t D7   = 13;
statisch const uint8_t D8   = 15;
statisch const uint8_t D9   = 3;
statisch const uint8_t D10  = 1;

struct WiFiEEPromData
{   dwaas APSTA = waar; // Toegangspunt of stationmodus - echte AP-modus   dwaas PwDReq = fout; // Wachtwoord vereist   dwaas CapPortal = waar ; // CaptivePortal aan in AP-modus   char APSTAName[APSTANAMELEN]; // STATION / AP Punt Naam TE VERBINDEN, indien definded   char WiFiPwd[WiFiPwdLen]; // WiFiPAssword, indien verdedigd   char ConfigValid[3]; // Als Config Vaild is, is tag "TK" vereist "
};

statisch const kort int BUILTIN_LED0 = D0; // GPIO0
/ * hostnaam voor mDNS. Moet op zijn minst werken op Windows. Probeer het maar http://esp8266.local */
const char *ESPHostname = "ESP";

// DNS-server
const byte DNS_PORT = 53;
DNS-server dnsServer;

// Conmmon Paramenters
dwaas SoftAccOK  = fout;

// webserver
ESP8266WebServer server(80);

/ * Soft AP-netwerkparameters * /
IP-adres apIP(172, 20, 0, 1);
IP-adres netMsk(255, 255, 255, 0);


/ ** Moet ik zo snel mogelijk verbinding maken met WLAN? * /
Boolean verbinden;

/ ** Laatste keer dat ik probeerde verbinding te maken met WLAN * /
// long lastConnectDo = 0;
niet ondertekend lang huidige Millis = 0;
niet ondertekend lang start Millis;
const kort periode = 10;  // Slaap na deze minuten inactiviteit


/ ** Huidige WLAN-status * /
kort status = WL_IDLE_STATUS;

WiFiEEPromData MyWiFiConfig;
String temp = "";

nietig instellen()
{   dwaas ConnectSuccess = fout;   dwaas CreateSoftAPSucc  = fout;   dwaas CInitFS-systeem  = fout;   dwaas CInitHTTPServer  = fout;   byte len;   pinMode(D0, UITGANG); // Initialiseer de BUILTIN_LED1-pin als uitvoer   Serie.beginnen(9600);   Serie.println();   Wifi.hostnaam(ESPHostname); // Stel de DHCP-hostnaam in die is toegewezen aan ESP-station.   als (loadCredentials()) // Laad WLAN-inloggegevens voor WiFi-instellingen   {     // Geldige referenties gevonden.     als (MyWiFiConfig.APSTA == waar)  // AP-modus     {       //Serial.println("AP Mode ");       //Serial.println(MyWiFiConfig.APSTA);       len = strlen(MyWiFiConfig.APSTAName);       MyWiFiConfig.APSTAName[len + 1] = '\0';       len = strlen(MyWiFiConfig.WiFiPwd);       MyWiFiConfig.WiFiPwd[len + 1] = '\0';       CreateSoftAPSucc = CreateWifiSoftAP();     } anders     {       //Serial.println("STA Mode ");       len = strlen(MyWiFiConfig.APSTAName);       MyWiFiConfig.APSTAName[len + 1] = '\0';       len = strlen(MyWiFiConfig.WiFiPwd);       MyWiFiConfig.WiFiPwd[len + 1] = '\0';       len = ConnectWifiAP();       als ( len == 3 ) {         ConnectSuccess = waar;       } anders {         ConnectSuccess = fout;       }     }   } anders   { // Set default Config - AP maken     Serie.println("DefaultWiFi Cnf");     SetDefaultWiFiConfig ();     CreateSoftAPSucc = CreateWifiSoftAP();     saveCredentials();     // Knipperen     digitalWrite(D0, LAAG); // Trek naar LAAG _LED AAN     vertraging(500);     digitalWrite(D0, HOOG);     vertraging(500);     digitalWrite(D0, LAAG); // Trek naar LAAG _LED AAN     vertraging(500);     digitalWrite(D0, HOOG);     vertraging(500);     digitalWrite(D0, LAAG); // Trek naar LAAG _LED AAN   }   als ((ConnectSuccess of CreateSoftAPSucc) en CInitFSSystem)   {     InitialiseerHTTPServer();     digitalWrite(D0, LAAG); // Trek naar LAAG _LED AAN     Serie.println("OK");   }   anders   {     Serie.setDebugOutput(waar); // Foutopsporingsoutput voor WLAN op seriële interface.     Serie.afdrukken("Err");     SetDefaultWiFiConfig ();     CreateSoftAPSucc = CreateWifiSoftAP();     saveCredentials();     InitialiseerHTTPServer();   }   start Millis = millis();  // initiële starttijd
}

nietig InitialiseerHTTPServer()
{   dwaas initok = fout;   / * Webpagina's instellen: root, wifi-configuratiepagina's, SO captive portal detectors en niet gevonden. * /   server.Aan("/", handleRoot);   server.Aan("/Wifi", handvatWifi);   als (MyWiFiConfig.CapPortal) {     server.Aan("/ genereren_204", handleRoot);  // Android captive portal. Misschien niet nodig. Kan worden behandeld door notFound-handler.   }   als (MyWiFiConfig.CapPortal) {     server.Aan("/favicon.ico", handleRoot);  // Nog een Android-captive portal. Misschien niet nodig. Kan worden behandeld door notFound-handler. Gecontroleerd op Sony Handy   }   als (MyWiFiConfig.CapPortal) {     server.Aan("/ fwlink", handleRoot);  // Microsoft captive portal. Misschien niet nodig. Kan worden behandeld door notFound-handler.   }   //server.on("/generate_204 ", handleRoot); // Android captive portal. Misschien niet nodig. Kan worden behandeld door notFound-handler.   //server.on("/favicon.ico ", handleRoot); // Nog een Android-captive portal. Misschien niet nodig. Kan worden behandeld door notFound-handler. Gecontroleerd op Sony Handy   //server.on("/fwlink ", handleRoot); // Microsoft captive portal. Misschien niet nodig. Kan worden behandeld door notFound-handler.   server.onNotFound ( handleNotFound );   // Speicherung Header-Element anfordern   // server.collectHeaders (Headers, sizeof (Headers) / sizeof (Headers [0]));   server.beginnen(); // Webserver start
}

Boolean CreateWifiSoftAP()
{   Wifi.verbinding verbreken();   Serie.afdrukken("SoftAP");   Wifi.softAPConfig(apIP, apIP, netMsk);   als (MyWiFiConfig.PwDReq)   {     SoftAccOK  =   Wifi.softAP(MyWiFiConfig.APSTAName, MyWiFiConfig.WiFiPwd); // Passwortlänge mindestens 8 Zeichen!   } anders   {     SoftAccOK  =  Wifi.softAP(MyWiFiConfig.APSTAName); // Toegangspunt ZONDER wachtwoord     // Overbelastingsfunctie :; WiFi.softAP (ssid, wachtwoord, kanaal, verborgen)   }   vertraging(600); // Zonder vertraging heb ik het IP-adres leeg gezien   als (SoftAccOK)   {     Serie.println("OK");     Serie.println(MyWiFiConfig.APSTAName);     Serie.println(MyWiFiConfig.WiFiPwd);     / * Stel de DNS-server in die alle domeinen omleidt naar de apIP * /     DNS server.setErrorReplyCode(DNSReplyCode::Geen fout);     DNS server.begin(DNS_PORT, "*", apIP);   } anders   {     Serie.println("fout");     Serie.println(MyWiFiConfig.APSTAName);     Serie.println(MyWiFiConfig.WiFiPwd);   }   terug SoftAccOK;
}


byte ConnectWifiAP()
{   // Serial.println ("Wifi-client initialiseren");   byte connRes = 0;   byte ik = 0;   Wifi.verbinding verbreken();   Wifi.softAPdisconnect(waar); // Functie stelt momenteel geconfigureerde SSID en wachtwoord van de soft-AP in op nulwaarden. De parameter is optioneel. Indien ingesteld op true, wordt de soft-AP-modus uitgeschakeld.   Wifi.beginnen(MyWiFiConfig.APSTAName, MyWiFiConfig.WiFiPwd);   connRes  = Wifi.waitForConnectResult();   vertraging(500);   terwijl (( connRes == 0 ) en (ik != 10))  // if connRes == 0 "IDLE_STATUS - Statius wijzigen"   {     connRes  = Wifi.waitForConnectResult();     vertraging(1000);     ik++;     Serie.println(".");     // verklaring (en)   }   terwijl (( connRes == 1 ) en (ik != 10))  // if connRes == 1 NO_SSID_AVAILin - SSID kan niet worden bereikt   {     connRes  = Wifi.waitForConnectResult();     vertraging(1000);     ik++;     Serie.println(".");     // verklaring (en)   }   als (connRes == 3 ) {     Serie.afdrukken("STA");     Wifi.setAutoReconnect(waar); // Stel in of de module probeert opnieuw verbinding te maken met een toegangspunt in het geval dat de verbinding wordt verbroken.     // MDNS-responder instellen     als (!MDNS.beginnen(ESPHostname)) {       Serie.println("Err: MDNS");     } anders {       MDNS.addService("http", "tcp", 80);     }   }   als (connRes == 4 ) {     Serie.println("STA Pwd Err");     //Serial.print("PwLen: ");     //Serial.println(strlen(MyWiFiConfig.WiFiPwd));     //Serial.print("PwSize ");     //Serial.println(sizeof(MyWiFiConfig.WiFiPwd));     Serie.println(MyWiFiConfig.APSTAName);     Serie.println(MyWiFiConfig.WiFiPwd);     Wifi.verbinding verbreken();   }   // if (connRes == 6) {Serial.println ("DISCONNECTED - Niet in stationmodus"); }   // WiFi.printDiag (serieel);   terug connRes;
}

dwaas loadCredentials()
{   dwaas RetValue;   EEPROM.beginnen(512);   EEPROM.krijgen(0, MyWiFiConfig);   EEPROM.einde();   als (Draad(MyWiFiConfig.ConfigValid) = Draad("TK"))   {     RetValue = waar;   } anders   {     RetValue = fout; // WLAN-instellingen niet gevonden.   }   terug RetValue;
}


/ ** WLAN-inloggegevens opslaan in EEPROM * /

dwaas saveCredentials()
{   dwaas RetValue;   // Controleer logische fouten   RetValue = waar;   als  (MyWiFiConfig.APSTA == waar ) // AP-modus   {     als (MyWiFiConfig.PwDReq en (De grootte van(Draad(MyWiFiConfig.WiFiPwd)) < 8))     {       RetValue = fout;  // Ongeldige configuratie     }     als (De grootte van(Draad(MyWiFiConfig.APSTAName)) < 1)     {       RetValue = fout;  // Ongeldige configuratie     }   } anders // Station-modus   {   }   // Eindcontrole logische fouten   als (RetValue)   {     EEPROM.beginnen(512);     voor (int ik = 0 ; ik < De grootte van(MyWiFiConfig) ; ik++)     {       EEPROM.schrijven(ik, 0);     }     strncpy( MyWiFiConfig.ConfigValid , "TK", De grootte van(MyWiFiConfig.ConfigValid) );     EEPROM.leggen(0, MyWiFiConfig);     EEPROM.plegen();     EEPROM.einde();   }   terug RetValue;
}

nietig SetDefaultWiFiConfig ()
{   byte len;   MyWiFiConfig.APSTA = waar;   MyWiFiConfig.PwDReq = waar;  // standaard PW vereist   MyWiFiConfig.CapPortal = waar;   strncpy( MyWiFiConfig.APSTAName, "My_WLANDevice", De grootte van(MyWiFiConfig.APSTAName) );   len = strlen(MyWiFiConfig.APSTAName);   MyWiFiConfig.APSTAName[len + 1] = '\0';   strncpy( MyWiFiConfig.WiFiPwd, "12345678", De grootte van(MyWiFiConfig.WiFiPwd) ); // geen wachtwoord   len = strlen(MyWiFiConfig.WiFiPwd);   MyWiFiConfig.WiFiPwd[len + 1] = '\0';   strncpy( MyWiFiConfig.ConfigValid, "TK", De grootte van(MyWiFiConfig.ConfigValid) );   len = strlen(MyWiFiConfig.ConfigValid);   MyWiFiConfig.ConfigValid[len + 1] = '\0';   Serie.println("RstWiFiCrd");
}

/ ** Is dit een IP? * /
Boolean isIp(Draad str) {   voor (int ik = 0; ik < str.lengte(); ik++) {     int c = str.charAt(ik);     als (c != '.' && (c < '0' || c > '9')) {       terug fout;     }   }   terug waar;
}

Draad GetEncryptionType(byte dit type) {   Draad Uitgang = "";   // lees het coderingstype en druk de naam af:   schakelaar (dit type) {     geval ENC_TYPE_WEP:       Uitgang = "WEP";       terug Uitgang;       breken;     geval ENC_TYPE_TKIP:       Uitgang = "WPA";       Terugkeer Output;       breken;     Zaak ENC_TYPE_CCMP:       Output = "WPA2";       Terugkeer Output;       breken;     Zaak ENC_TYPE_NONE:       Output = "Geen";       Terugkeer Output;       breken;     Zaak ENC_TYPE_AUTO:       Output = "Auto".;       Terugkeer Output;       breken;   }
}

OT / * * te knopen
String toStringIp(IPAD jurk OT) {   String res = "";   Voor (int Ik = 0; Ik < 3; Ik++) {     res += String((OT >> (8 * Ik)) & 0xFF) + ".";   }   res += String(((OT >> 8 * 3)) & 0xFF);   Terugkeer res;
}


String formaat bytes(size_t bytes) {            //readable tonen van de afmetingen geheugen   Als (bytes < 1024) {     Terugkeer String(bytes) + "Byte";   } Anders Als (bytes < (1024 * 1024)) {     Terugkeer String(bytes / 1024.0) + "KB";   } Anders Als (bytes < (1024 * 1024 * 1024)) {     Terugkeer String(bytes / 1024.0 / 1024.0) + "MB";   }
}






Leegte handleRoot() {   Belangrijkste //the pagina:   //FSInfo fs_info;   Uitzendkracht = "";   Korte PicCount = 0;   byte ServArgs = 0;   //Building pagina   //HTML kop   server.sendHeader("Cache-Control", "Geen cache geen winkel, must-revalidate");   server.sendHeader("Pragma", "Geen cache");   server.sendHeader("Afloopt", "-1");   server.setContentLength(CONTENT_LENGTH_UNKNOWN);   //HTML inhoud   server.sturen ( 200, "text / html", Uitzendkracht );   Geheugen //send bezuinigd - reeds voor de Cleint   Uitzendkracht = "";   Uitzendkracht += "<! DOCTYPE HTML>, < lang = html" de ">, <, head>, <, meta name = tekenset" UTF-8 ">, <, meta = inhoud blikveld =" = breedte breedte apparaat, schaal 1.0 = eerste, ">";   server.sendContent(Uitzendkracht);   Uitzendkracht = "";   Uitzendkracht += "<, type style =" text / css ">, <! - DIV.container {min hoogte: ze 10em; display: tabelcel; vertical-align:} {midden .button hoogte 35px; Breedte 90px; Lettergrootte 16px} ";   server.sendContent(Uitzendkracht);   Uitzendkracht = "";   Uitzendkracht += "Lichaam {achtergrondkleur: Poederblauwcolor;} < /style>;";   Uitzendkracht += "<, head>, <, title>, gevangen Portal<, /title>, < /head>;";   Uitzendkracht += "<, h2>, gevangen Portal< /h2>;";   Uitzendkracht += "< body>;";   server.sendContent(Uitzendkracht);   Uitzendkracht = "";   Uitzendkracht += "<, br>, <, zie tabel grens = 2 bgcolor = wit breedte = 500 cellpadding = 5 >, <, caption>, <, p>, <, h3>, Sytemlinks:<, /h2>, <, /p>, < /caption>;";   Uitzendkracht += "<, tr>, <, th>, < br>;";   Uitzendkracht += "< a href="/nl/ wifi" >, WIFI Einstellungen<, /a>, <, br>, < br>;";   Uitzendkracht += "<, /th>, <, /tr>, <, /table>, <, br>, < br>;";   //temp = "<, footer>, <, p>, geprogrammeerd en ontworpen door: Tobias kuch<, /p>, <, p>, contactinformatie: < = a href" mailto tobias.kuch@googlemail.com ">, tobias.kuch@googlemail.com <, /a>, .<, /p>, < /footer>;".   Uitzendkracht += "<, /body>, < /html>;";   server.sendContent(Uitzendkracht);   Uitzendkracht = "";   server.cliënt().Stoppen(); //Stop is noodzakelijk, omdat we geen lengte stuurde inhoud
}



Leegte handleNotFound() {   Als (captivePortal())   { //If caprive hoofdingang sturen in plaats van fout bij het tonen van de pagina.     Terugkeer;   }   Uitzendkracht = "";   //HTML kop   server.sendHeader("Cache-Control", "Geen cache geen winkel, must-revalidate");   server.sendHeader("Pragma", "Geen cache");   server.sendHeader("Afloopt", "-1");   server.setContentLength(CONTENT_LENGTH_UNKNOWN);   //HTML inhoud   Uitzendkracht += "<! DOCTYPE HTML>, < lang = html" de ">, <, head>, <, meta name = tekenset" UTF-8 ">, <, meta = inhoud blikveld =" = breedte breedte apparaat, schaal 1.0 = eerste, ">";   Uitzendkracht += "<, type style =" text / css ">, <! - DIV.container {min hoogte: ze 10em; display: tabelcel; vertical-align:} {midden .button hoogte 35px; Breedte 90px; Lettergrootte 16px} ";   Uitzendkracht += "Lichaam {achtergrondkleur: Poederblauwcolor;} < /style>;";   Uitzendkracht += "<, head>, <, title> bestand found<, /title>, < /head>;";   Uitzendkracht += "h2> <; 404 bestanden moeten Found<, /h2>, < br>; ";   Uitzendkracht += "<, h4>, debuggen Information:<, /h4>, < br>;";   Uitzendkracht += "< body>;";   Uitzendkracht += "URI:";   Uitzendkracht += server.Uri();   Uitzendkracht += "\nMethod:";   Uitzendkracht += ( server.Methode() == HTTP_GET ) ? "Gaan". : "POST";   Uitzendkracht += "<, br> argumenten:;";   Uitzendkracht += server.Argumenten();   Uitzendkracht += "\n";   Voor ( uint8_t Ik = 0; Ik < server.Argumenten(); Ik++ ) {     Uitzendkracht += " " + server.Slechte naam ( Ik ) + ": " + server.Slecht ( Ik ) + "\n";   }   Uitzendkracht += "<, br> - server Hostheader:" + server.hostHeader();   Voor ( uint8_t Ik = 0; Ik < server.Koppen(); Ik++ ) {     Uitzendkracht += " " + server.headerName ( Ik ) + ": " + server.header ( Ik ) + "\n< br>;";   }   Uitzendkracht += "<, /table>, <, /form>, <, br>, <, br>, <, zie tabel grens = 2 bgcolor = wit breedte = 500 cellpadding = 5 >, <, caption>, <, p>, <, h2>, u kunt wilt bladeren to:<, /h2>, <, /p>, < /caption>;";   Uitzendkracht += "<, tr>, < th>;";   Uitzendkracht += "< a href="/nl"> voornaamste Page<, /a>, < br>;";   Uitzendkracht += "< a href="/nl/ wifi" >, WIFI Settings<, /a>, < br>;";   Uitzendkracht += "<, /th>, <, /tr>, <, /table>, <, br>, < br>;";   //temp = "<, footer>, <, p>, geprogrammeerd en ontworpen door: Tobias kuch<, /p>, <, p>, contactinformatie: < = a href" mailto tobias.kuch@googlemail.com ">, tobias.kuch@googlemail.com <, /a>, .<, /p>, < /footer>;".   Uitzendkracht += "<, /body>, < /html>;";   server.sturen ( 404, "", Uitzendkracht );   server.cliënt().Stoppen(); //Stop is noodzakelijk, omdat we geen lengte stuurde inhoud   Uitzendkracht = "";

}




/ * In gevangenschap levende omleiden naar de hoofdingang als er een verzoek om een ander domein. Waar terug in dat geval dus de begeleider de pagina proberen te besluiten het verzoek opnieuw */
boolean captivePortal() {   Als (!isIp(server.hostHeader()) && server.hostHeader() != (String(ESPHostname) + ".local")) {     //Serial.println ("verzoek doorgestuurd naar portaal voor intern gebruik");     server.sendHeader("Locatie", String("http://") + toStringIp(server.cliënt().localIP()), Waar);     server.sturen ( 302, "text / plain", ""); //Empty remt header inhoud Inhoudslengte moet dus het onszelf sluit de socket.     server.cliënt().Stoppen(); //Stop is noodzakelijk, omdat we geen lengte stuurde inhoud     Terugkeer Waar;   }   Terugkeer Valse;
}



* Config / begeleider Wifi pagina */
Leegte handleWifi()
{   //Page:/wifi   byte Ik;   byte len ;   Uitzendkracht = "";   //Check dat site van parametre   Als (server.hasArg("Reboot") )  //Reboot systeem   {     Uitzendkracht = "Herstarten systeem binnen 5 seconden.";     server.sturen ( 200, "text / html", Uitzendkracht );     Vertraging(5000);     server.cliënt().Stoppen();     WiFi.Verbinding verbreken();     Vertraging(1000);     pinMode(D6, OUTPUT);     digitalWrite(D6, LAAG);   }   Als (server.hasArg("WiFiMode") en (server.Slecht("WiFiMode") == "1")  )  WTA //station mode een ander station verbinden met WIFI   {     startMillis = millis(); Teller //reset tijd zien te vermijden die whiole stationair draaien     Aan de bestaande STATION //connect     Als ( sizeof(server.Slecht("WiFi_Network")) > 0  )     {       Serie.println("Mode STA");       MyWiFiConfig.APSTA = Valse; Station //access punt of fashion - fashion valse station       Uitzendkracht = "";       Voor ( Ik = 0; Ik < APSTANameLen; Ik++) {         MyWiFiConfig.APSTAName[Ik] =  0;       }       Uitzendkracht = server.Slecht("WiFi_Network");       len =  Uitzendkracht.Lengte();       Voor ( Ik = 0; Ik < len; Ik++)       {         MyWiFiConfig.APSTAName[Ik] =  Uitzendkracht[Ik];       }       //MyWiFiConfig. APSTAName [1 len] \0 '=';       Uitzendkracht = "";       Voor ( Ik = 0; Ik < WiFiPwdLen; Ik++)  {         MyWiFiConfig.WiFiPwd[Ik] =  0;       }       Uitzendkracht = server.Slecht("STAWLanPW");       len =  Uitzendkracht.Lengte();       Voor ( Ik = 0; Ik < len; Ik++)       {         Als (Uitzendkracht[Ik] > 32) //Tax signalen sturen         {           MyWiFiConfig.WiFiPwd[Ik] =  Uitzendkracht[Ik];         }       }       //MyWiFiConfig. WiFiPwd [1 len] \0 '=';       Uitzendkracht = "WiFi verbinding maken met AP.";       Uitzendkracht += MyWiFiConfig.APSTAName;       Uitzendkracht += "- <, br> PW WiFi.";       Uitzendkracht += MyWiFiConfig.WiFiPwd;       Uitzendkracht += "- < br>;";       Uitzendkracht += "Toegang krijgen tot mode WTA in 2 Seconds.< br>;";       server.sturen ( 200, "text / html", Uitzendkracht );       server.sendContent(Uitzendkracht);       Vertraging(2000);       server.cliënt().Stoppen();       server.Stoppen();       Uitzendkracht = "";       WiFi.Verbinding verbreken();       WiFi.softAPdisconnect(Waar);       Vertraging(500);       //ConnectWifiAP       bool SaveOk = saveCredentials();       pinMode(D6, OUTPUT);       digitalWrite(D6, LAAG);       Ik = ConnectWifiAP();       Vertraging(700);       Als (Ik != 3) - //4 WL_CONNECT_FAILED paspoort is onjuist woord 1: - SSID WL_NO_SSID_AVAILin geconfigureerd kan worden bereikt       {         Serie.Afdrukken("Err STA");         Serie.println(Ik);         server.cliënt().Stoppen();         Vertraging(100);         WiFi.setAutoReconnect (Valse);         Vertraging(100);         WiFi.Verbinding verbreken();         Vertraging(1000);         pinMode(D6, OUTPUT);         digitalWrite(D6, LAAG);         Terugkeer;       } Anders       {         //Safe Config         bool SaveOk = saveCredentials();         InitalizeHTTPServer();         Terugkeer;       }     }   }   Als (server.hasArg("WiFiMode") en (server.Slecht("WiFiMode") == "2")  )  AP //change mode   {     startMillis = millis(); Teller //reset tijd zien te vermijden die whiole stationair draaien     //Configure toegangspunt     Uitzendkracht = server.Slecht("APPointName");     len =  Uitzendkracht.Lengte();     Uitzendkracht = server.Slecht("APPW");     Als (server.hasArg("PasswordReq"))     {       Ik =  Uitzendkracht.Lengte();     } Anders {       Ik = 8;     }     Als (  ( len > 1 ) en (server.Slecht("APPW") == server.Slecht("APPWRepeat")) en ( Ik > 7)          )     {       Uitzendkracht = "";       Serie.println("APMode");       MyWiFiConfig.APSTA = Waar; //Access punt of waar jonge mode - AP mode       Als (server.hasArg("CaptivePortal"))       {         MyWiFiConfig.CapPortal = Waar ; Op //captiveportal van AP mode       } Anders {         MyWiFiConfig.CapPortal = Valse ;       }       Als (server.hasArg("PasswordReq"))       {         MyWiFiConfig.PwDReq = Waar ; //Passport woord in de mode vereiste AP       } Anders {         MyWiFiConfig.PwDReq = Valse ;       }       Voor ( Ik = 0; Ik < APSTANameLen; Ik++) {         MyWiFiConfig.APSTAName[Ik] =  0;       }       Uitzendkracht = server.Slecht("APPointName");       len =  Uitzendkracht.Lengte();       Voor ( Ik = 0; Ik < len; Ik++) {         MyWiFiConfig.APSTAName[Ik] =  Uitzendkracht[Ik];       }       MyWiFiConfig.APSTAName[len + 1] = '\0';       Uitzendkracht = "";       Voor ( Ik = 0; Ik < WiFiPwdLen; Ik++)  {         MyWiFiConfig.WiFiPwd[Ik] =  0;       }       Uitzendkracht = server.Slecht("APPW");       len =  Uitzendkracht.Lengte();       Voor ( Ik = 0; Ik < len; Ik++)  {         MyWiFiConfig.WiFiPwd[Ik] =  Uitzendkracht[Ik];       }       MyWiFiConfig.WiFiPwd[len + 1] = '\0';       Uitzendkracht = "";       Als (saveCredentials()) AP //save ConfigCongfig       {         Uitzendkracht = "Gegevens van de supermarkt. Modi met succes opgeslagen. Onvermijdelijk opnieuw opstarten. ";       } Anders  {         Uitzendkracht = "Gegevens van de supermarkt. gebrekkig vormen.";       }     } Anders Als (server.Slecht("APPW") != server.Slecht("APPWRepeat"))     {       Uitzendkracht = "";       Uitzendkracht = "WLAN wachtwoord niet meteen. Uncompletedly. ";     } Anders     {       Uitzendkracht = "";       Uitzendkracht = "WLAN wachtwoord of AP naam te kort. Uncompletedly. ";     }     //WifiAP   }   //HTML kop   server.sendHeader("Cache-Control", "Geen cache geen winkel, must-revalidate");   server.sendHeader("Pragma", "Geen cache");   server.sendHeader("Afloopt", "-1");   server.setContentLength(CONTENT_LENGTH_UNKNOWN);   //HTML inhoud   Uitzendkracht += "<! DOCTYPE HTML>, < lang = html" de ">, <, head>, <, meta name = tekenset" UTF-8 ">, <, meta = inhoud blikveld =" = breedte breedte apparaat, schaal 1.0 = eerste, ">";   server.sturen ( 200, "text / html", Uitzendkracht );   Uitzendkracht = "";   Uitzendkracht += "<, type style =" text / css ">, <! - DIV.container {min hoogte: ze 10em; display: tabelcel; vertical-align:} {midden .button hoogte 35px; Breedte 90px; Lettergrootte 16px} ";   Uitzendkracht += "Lichaam {achtergrondkleur: Poederblauwcolor;} <, /style>, <, head>, <, title>, slimmerik naamplaat - WiFi Settings<, /title>, < /head>;";   server.sendContent(Uitzendkracht);   Uitzendkracht = "";   Uitzendkracht += "<, h2>, WiFi Einstellungen<, /h2>, <, body>, < left>;";   Uitzendkracht += "<, zie tabel grens = 2 bgcolor = wit breedte = 500 >, <, td>, <, h4>, geldende WiFi instellingen: < /h4>;";   Als (server.cliënt().localIP() == apIP) {     Uitzendkracht += "Fashion: zachtjes toegangspunt (AP) < br>;";     Uitzendkracht += "SSID:" + String (MyWiFiConfig.APSTAName) + "<, br>, < br>;";   } Anders {     Uitzendkracht += "Fashion: Station (WTA) < br>;";     Uitzendkracht += "SSID:" + String (MyWiFiConfig.APSTAName) + "< br>;";     Uitzendkracht += "BSSID:" + WiFi.BSSIDstr() + "<, br>, < br>;";   }   Uitzendkracht += "<, /td>, <, /table>, < br>;";   server.sendContent(Uitzendkracht);   Uitzendkracht = "";   Uitzendkracht += "<, formulieractie = '/ wifi methode' =" post ">";   Uitzendkracht += "<, zie tabel grens = 2 bgcolor = wit width = 500>, <, tr>, <, th>, < br>;";   Als (MyWiFiConfig.APSTA == 1)   {     Uitzendkracht += "<, inbreng type =" radio "= waarde" 1 de naam van '= WiFiMode "> WiFi station Mode< br>; ";   } Anders   {     Uitzendkracht += "<, inbreng type =" radio "= waarde" 1 de naam van '= WiFiMode "> gecontroleerd; WiFi station Mode< br>; ";   }   Uitzendkracht += "Beschikbare WiFi Networks:<, zie tabel grens = 2 bgcolor = wit >, <, /tr>, <, /th>, <, td>, aantal <, /td>, <, td>, SSID <, /td>, <, td>, versleuteling <, /td>, <, td>, WiFi kracht < /td>;";   server.sendContent(Uitzendkracht);   Uitzendkracht = "";   WiFi.scanDelete();   int N = WiFi.scanNetworks(Valse, Valse); //WiFi.scanNetworks (, async show_hidden)   Als (N > 0) {     Voor (int Ik = 0; Ik < N; Ik++) {       Uitzendkracht += "<, /tr>, < /th>;";       String Nrb = String(Ik);       Uitzendkracht += "< td>;" + Nrb + "< /td>;";       Uitzendkracht += "< td>;" + WiFi.SSID(Ik) + "< /td>;";       Nrb = GetEncryptionType(WiFi.encryptionType(Ik));       Uitzendkracht += "< td>;" + Nrb + "< /td>;";       Uitzendkracht += "< td>;" + String(WiFi.RSSI(Ik)) + "< /td>;";     }   } Anders {     Uitzendkracht += "<, /tr>, < /th>;";     Uitzendkracht += "<, td> 1 < /td>;";     Uitzendkracht += "<, td>, noch is er een WLAN found< /td>;";     Uitzendkracht += "<, td> - < /td>;";     Uitzendkracht += "<, td> - < /td>;";   }   Uitzendkracht += "<, /table>, <, zie tabel grens = 2 bgcolor = wit >, <, /tr>, <, /th>, <, td>, verbinden met WiFi SSID: <, /td>, <, td>, < kies name =" WiFi_Network ">";   Als (N > 0) {     Voor (int Ik = 0; Ik < N; Ik++) {       Uitzendkracht += "< mogelijkheid waarde = '" + WiFi.SSID(Ik) + "'>" + WiFi.SSID(Ik) + "< /option>;";     }   } Anders {     Uitzendkracht += "< mogelijkheid value =" No_WiFi_Network "> en niemand WiFiNetwork gevonden /option>!";   }   server.sendContent(Uitzendkracht);   Uitzendkracht = "";   Uitzendkracht += "<, /select>, <, /td>, <, /tr>, <, /th>, <, /tr>, <, /th>, <, td>, WiFi paspoort woord: <, /td>, < td>;";   Uitzendkracht += "<, inbreng type =" tekst "naam van =" STAWLanPW "= in maxlength" 40 "= grootte" 40 ">";   Uitzendkracht += "<, /td>, <, /tr>, <, /th>, <, br>, <, /th>, <, /tr>, <, /table>, <, /table>, <, zie tabel grens = 2 bgcolor = wit breedte = 500 >, <, tr>, <, th>, < br>;";   server.sendContent(Uitzendkracht);   Uitzendkracht = "";   Als (MyWiFiConfig.APSTA == Waar)   {     Uitzendkracht += "<, inbreng type =" radio "naam van =" WiFiMode "= 'waarde 2' checked> Wifi-accesspoint mode < br>; ";   } Anders   {     Uitzendkracht += "<, inbreng type =" radio "naam van =" WiFiMode "= 'waarde 2' > Wifi-accesspoint mode < br>; ";   }   Uitzendkracht += "<, zie tabel grens = 2 bgcolor = wit >, <, /tr>, <, /th>, <, td>, wifi-accesspoint naam: <, /td>, < td>;";   server.sendContent(Uitzendkracht);   Uitzendkracht = "";   Als (MyWiFiConfig.APSTA == Waar)   {     Uitzendkracht += "<, inbreng type =" tekst "naam van =" APPointName "maxlength = '" + String(APSTANameLen - 1) + "De grootte van = in" 30 "waarde = '" + String(MyWiFiConfig.APSTAName) + ">, < /td>;";   } Anders   {     Uitzendkracht += "<, inbreng type =" tekst "naam van =" APPointName "maxlength = '" + String(APSTANameLen - 1) + "De grootte van = in" 30 ">, < /td>;";   }   server.sendContent(Uitzendkracht);   Uitzendkracht = "";   Als (MyWiFiConfig.APSTA == Waar)   {     Uitzendkracht += "<, /tr>, <, /th>, <, td>, WiFi paspoort woord: <, /td>, < td>;";     Uitzendkracht += "<, inbreng type =" wachtwoord "naam van =" APPW "maxlength = '" + String(WiFiPwdLen - 1) + "De grootte van = in" 30 "waarde = '" + String(MyWiFiConfig.WiFiPwd) + ">, < /td>;";     Uitzendkracht += "<, /tr>, <, /th>, <, td>, herhaal WiFi wachtwoord < /td>;";     Uitzendkracht += "<, td>, <, inbreng type =" wachtwoord "naam van =" APPWRepeat "maxlength = '" + String(WiFiPwdLen - 1) + "De grootte van = in" 30 "waarde = '" + String(MyWiFiConfig.WiFiPwd) + ">, < /td>;";   } Anders   {     Uitzendkracht += "<, /tr>, <, /th>, <, td>, WiFi paspoort woord: <, /td>, < td>;";     Uitzendkracht += "<, inbreng type =" wachtwoord "naam van =" APPW "maxlength = '" + String(WiFiPwdLen - 1) + "De grootte van =" 30 ">, < /td>;";     Uitzendkracht += "<, /tr>, <, /th>, <, td>, herhaal WiFi wachtwoord < /td>;";     Uitzendkracht += "<, td>, <, inbreng type =" wachtwoord "naam van =" APPWRepeat "maxlength = '" + String(WiFiPwdLen - 1) + "De grootte van =" 30 ">, < /td>;";   }   Uitzendkracht += "< /table>;";   server.sendContent(Uitzendkracht);   Uitzendkracht = "";   Als (MyWiFiConfig.PwDReq)   {     Uitzendkracht += "<, inbreng type =" optie "naam van" PasswordReq "= checked> Paspoort woord voor aanmelding vereist. ";   } Anders   {     Uitzendkracht += "<, inbreng type =" optie "naam van" PasswordReq "= > Paspoort woord voor aanmelding vereist. ";   }   server.sendContent(Uitzendkracht);   Uitzendkracht = "";   Als (MyWiFiConfig.CapPortal)   {     Uitzendkracht += "<, inbreng type =" optie "naam van" CaptivePortal "= checked> Activeren hoofdingang gevangen ";   } Anders   {     Uitzendkracht += "<, inbreng type =" optie "naam van" CaptivePortal "= > Activeren hoofdingang gevangen ";   }   server.sendContent(Uitzendkracht);   Uitzendkracht = "";   Uitzendkracht += "<, br>, <, /tr>, <, /th>, <, /table>, <, br>, < knopen type =" submit "= naam van" instellingen "waarde = styles '1' = '50px; hoogte: breedte: 140px 'autofocus>, en dat alles WIFI Settings< /button>; ";   Uitzendkracht += "< knopen type =" submit "naam van =" Reboot "waarde = styles '1' = '50px; hoogte: breedte: 200px '>, herstarten System< /button>; ";   server.sendContent(Uitzendkracht);   Uitzendkracht = "";   Uitzendkracht += "< knopen type =" reset "= naam van" actie "= waarde '1' stijlen ': = hoogte 50px; breedte: 100px '>, Reset<, /button>, < /form>; ";   Uitzendkracht += "<, zie tabel grens = 2 bgcolor = wit breedte = 500 cellpadding = 5 >, <, caption>, <, p>, <, h3>, Sytemlinks:<, /h2>, <, /p>, <, /caption>, <, tr>, <, th>, < br>;";   server.sendContent(Uitzendkracht);   Uitzendkracht = "";   Uitzendkracht += "< a href="/nl"> voornaamste Page<, /a>, <, br>, <, br>, <, /th>, <, /tr>, <, /table>, <, br>, < br>;";   //temp = "<, footer>, <, p>, geprogrammeerd en ontworpen door: Tobias kuch<, /p>, <, p>, contactinformatie: < = a href" mailto tobias.kuch@googlemail.com ">, tobias.kuch@googlemail.com <, /a>, .<, /p>, < /footer>;".   Uitzendkracht += "<, /body>, < /html>;";   server.sendContent(Uitzendkracht);   server.cliënt().Stoppen(); //Stop is noodzakelijk, omdat we geen lengte stuurde inhoud   Uitzendkracht = "";
}

# define SD_BUFFER_PIXELS 20

Leegte Lus()
{   Als (SoftAccOK)   {     DNS-server.processNextRequest(); //DNA   }   //HTTP   server.handleClient();   opbrengst();
}

 

 

Ik wil een hoop plezier met test van de hoofdingang gevangene van en met de eigen projecten ten uitvoer te leggen.

Esp-8266Projekte für fortgeschrittene

15 Reacties

Ludwig

Ludwig

Vielen Dank für das schöne Projekt.

Bei der Beschäftigung damit bin ich auf eine minimalistische Alternative gestoßen, nämlich “ESPConnect”. Es handelt sich ebenfalls um ein Captive Portal, über das eine WiFi-Verbindung eingerichtet werden kann. Die Einfachheit des Implementierung ist nicht zu übertreffen – es sind nur ein paar Zeilen Code erforderlich. Die Bibliothek läuft sowohl auf dem ESP8266 als auch auf dem ESP32.

Man kann die Bibliothek über die Arduino-Bibliotheksverwaltung einbinden. Es steht dann ein Beispiel zur Verfügung.

Gruß

Ludwig

MaKo

MaKo

Hallo ,
Danke , das Portal funktioniert nach Beseitigung der Compilerfehlermeldungen (fix Portzuweisungen erstellt! Ja ich weiß portabler Code schaut anders aus) Aber zunächst muß der Code ja erst mal übersetzt werden.
Bei mir erscheint das Portal nur auf einem alten Windows mobile! Bei anderen Mobiles (Android devices) kann ich nur die Netzwerkinfo Seite anschauen?? Habe dann auf dem WinGerät meine Home SSID und mein Passwrt eingegeben. Aber nach Netztrennenung und wieder anschalten ist wieder nur My_WlANDevice aktive!
Ich würde gerne meine 8-10 ESP Knoten die mit Mosquitto MQTT Brooker arbeiten und fix mit meinem Heim-Netzwerk verbunden sind mit dem Captive portal verknüpfen, weiss aber nicht wie ich das bewerkstelligen soll! (wenn denn die Auswahl erhalten bliebe) gibts da noch eine Anleitung ?
Bedanke mich schon mal im vorraus
Gruß Martin

ILIJA

ILIJA

Hello Tobias,
I see mistake in the loadCredentials():
if (String(MyWiFiConfig.ConfigValid) = String(“TK”)) —> it will not work correctly.
Shall be:
if (String(MyWiFiConfig.ConfigValid) == String(“TK”)) —> use “==” intead of “=”

Same for ESP32.

Regards
Ilija

Rudolf Schenke

Rudolf Schenke

Mit der von mit vermuteten Änderung (Vereinfachen des if-Ausdrucks) läuft es!!

Rudolf Schenke

Rudolf Schenke

Im Code muss ein Fehler sein!? Nach jedem Reset landet der ESP wieder im AP-Mode.
Die vermutete Fehlerquelle:
– in setup() oben: bool CInitFSSystem = false;
– in setup() weiter unten: if ((ConnectSuccess or CreateSoftAPSucc) and CInitFSSystem) Da die Variable “CInitFSSystem” nie auf “true” gesetzt wird, kommt das Programm auch nie weiter.

Th. Springer

Th. Springer

Hallo zusammen,

ohne diese Werte geht auch das Compilieren des Codes und auch die Funktion dazu auf einem ESP8266.
-——————————————————————————
static const uint8_t D0 = 16;
static const uint8_t D1 = 5;
static const uint8_t D2 = 4;
static const uint8_t D3 = 0;
static const uint8_t D4 = 2;
static const uint8_t D5 = 14;
static const uint8_t D6 = 12;
static const uint8_t D7 = 13;
static const uint8_t D8 = 15;
static const uint8_t D9 = 3;
static const uint8_t D10 = 1;
-———————————————————————————-
Im GitHub Portal ist das nicht drin !

mfg
Th. Springer

Alex

Alex

Danke für den Blogbeitrag!
Wenn man aber nicht alles selber machen will, gibt es die fertige Bibliothek “WifiManager” (MIT Lizenz) für den ESP8266 ;)

https://github.com/tzapu/WiFiManager

Rolf Schatten

Rolf Schatten

Super Idee, unter welcher Lizenz steht der Code?

Ralf Krämer

Ralf Krämer

Hallo,

hat das schon jemand mit einem esp32 umgesetzt?
Ich gehe mal davon aus, dass es die includes alle für esp32 gibt.

Gruß
Ralf

Jürgen Willnecker

Jürgen Willnecker

Schöne Idee, dieses grundlegende Problem als source code zur Verfügung zu stellen.

Ich würde mir bei den externen Spezialaufrufen einen erklärenden Kommentar wünschen.

Im code Hardwareanschlüsse (D0, D6) direkt anzusprechen, führt zu Fehlern beim Wechsel des Boards. Ein “no-go”.

Bei meinem Wemos D1 liegt die blaue BuildInLED auf D4. Bei einem ESP-01 mal so, mal anders (es gibt hier 2 verschiedene Versionen).
const int LED_blue1 = 2; // blaue LED (ESP-01S) – Board #1
const int LED_blue2 = 1; // blaue LED (ESP-01S) – Board #2

D0 erklärt sich jedoch über eine Definition im source code.
Aber D6? Muss da mit Reset gebrückt werden? Wozu ist ein LOW erforderlich?

Christian Zittier

Christian Zittier

Vorerst mal Danke jedoch hab ich aufgrund meiner Unwissenheit ein Problem mit dem Code.
Nach dem Flashvorgang (NodeMCU V3) sehe ich im Browser die Seite stelle wie beschrieben die WLan Einstellungen um er Übernimmt auch das Netzwerk und ist unter der neuen IP verfügbar aber nach einem Reset oder Stromausfall ist alles weg.
Eigentlich sollte der neue WLan Zugang im EEprom gespeichert werden macht es aber offensichtlich nicht? Bei einem Reboot von der Webseite aus bleiben die WLan Einstellungen erhalten

Hab auch mehrere Bord Einstellungen probiert jedoch ohne erfolg.
Würde mich freuen wenn mann mir auf die Sprünge hilft wollte auch ein fertiges funktionierendes Projekt mit meinen MQTT-Brocker integrieren (WLan Einstellungen aus dem Projekt entfernt und mit diesem Code ersetzt geht leider auch nicht irgendwie bin ich einfach zu Blöd. Mein Gedanke selbst wenn nach einem Neustart die WLan Einstellungen weg sind und ich nicht weiß warum, so müsste ja nach dem Anpassen der WLan Einstellungen das integrierte Projekt doch funktionieren?

l.g. Christian

Ilias

Ilias

Hallo Tobias,

vielen Dank, wirklich eine schöne Idee und optisch sehr ansprechend.

Daher habe es auch gleich auf einem “AZ-Delivery NodeMCU ESP8266-12E mit OLED Display” ausprobiert – leider mit mäßigem Erfolg:

Der AP-Mode funzt Wechsel in den Server-Mode funktioniert nur selten. Meistens wird wieder in den AP-Mode gewechselt. Beim Versuch, mit dem Handy (Adroid, Samsung S7 und S9) zuzugreifen eine Meldung dass es eine unseicher Verbindung sei und daher der Zugriff unterbunden wird (AP und Server-Mode). Wenn man die Daten für den AP-Mode ändern will, werden die Änderungen nicht im EEPROM gespeichert. Es ist bleiben immer die Default-Werte.

Leider sind die Meldungen auf der Seriellen Schnittstelle teilweise sehr kryptisch, was ein Debuggen erschwert.

Hat wer eine Idee, wie man das Programm verbessern kann, so dass es stabil läuft?
Zusatzfrage: Ich möchte die jeweilig IP-Adresse auf dem OLED ausgeben. Konnte aber weder die passenden stellen im Programm, noch den Funkitonsaufruf für die IP finden.

Grüße,
Ilias

Ulrich Klaas

Ulrich Klaas

Hallo,
das Portal funktioniert. Ich kann mit dem Handy zugreifen und die Zugangsdaten meines Routers eintragen. Wenn ich danach aber neu boote bleibt nach wie vor der Accesspoint
sichtbar und die NodeMCU verbindet sich nicht mit meinem Router.

Ich habe allerdings den Namen des Portals geändert. Das kann aber wohl nicht der Grund sein, oder ?

Ulrich Klaas

Ulrich Klaas

Was sollen den die Constdefinitionen von D0 – D10 ?
Ich kriege da Fehlermeldungen weil die natürlich schon definiert sind (NodeMCU).

Nehme ich die raus compiliert es.
Ulli

Hermann Schönbauer

Hermann Schönbauer

Super!!! Habe es bisher über eine starre “Notverbindung” zu einer fixen SSID gelöst. Aber so ist es wesentlich eleganter und überall einsetzbar.
Gratuliere
Hermann

Laat een reactie achter

Alle opmerkingen worden voor publicatie gecontroleerd door een moderator

Aanbevolen blogberichten

  1. ESP32 jetzt über den Boardverwalter installieren - AZ-Delivery
  2. Internet-Radio mit dem ESP32 - UPDATE - AZ-Delivery
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1 - AZ-Delivery
  4. ESP32 - das Multitalent - AZ-Delivery