Mit dem Over The Air Update kann man einen neuen Sketch über eine WLAN-Verbindung auf ein ESP8266 Modul wie z. B. dem Wemos D1 hochladen. Ein kleiner Nachteil, der Serial Monitor funktioniert leider nicht ohne direkte USB-Verbindung. Probiert man es dennoch den Serial Monitor zu starten, erscheint die Fehlermeldung “Serial monitor is not supported on network ports such as X.X.X.X for the null in this release” und es passiert nichts. Ein Wifi Telnet Server kann Abhilfe schaffen und erlaubt ein Debugging über das Telnet Protokoll im gesamten Netzwerk. Es wird dafür keine Arduino IDE benötigt, ein einfacher Telnet Client wie PuTTY reicht aus.
Der Wifi Telnet Server ist so aufgebaut, dass er mehrere Telnet Verbindungen annehmen kann. Das ist gerade in komplexen Projekten sehr praktisch, denn so können auch mehrere Personen gleichzeitig die Meldungen lesen. Wurde die im Sketch definierte maximale Anzahl von Verbindungen (MAX_TELNET_CLIENTS) erreicht, werden weitere Verbindung abgelehnt. Wird eine Verbindung geschlossen, kann die Sitzung wieder für eine neue Verbindung verwendet werden. Wenn ihr noch mit dem ESP8266 verbunden seid, seht ihr die einzelnen Telnet Verbindungen im Serial Monitor.
Als Telnet Client auf einem Windows Endgerät kann ich PuTTY empfehlen oder ihr installiert den Windows Telnet Client. Für Android oder iOS gibt es genügend (freie) Apps. Das Telnet nicht gerade das sicherste Protokoll ist muss ich hier hoffentlich nicht erwähnen?!
Telnet Nachricht senden
Um eine Nachricht an jeden verbundenen Telnet Client zu senden, habe ich eine kleine Funktion (TelnetMsg) erstellt. Ihr könnt diese anstelle oder zusätzlich zu Serial.print in den Sketch einbauen.
Mit dem folgenden Beispiel kann z. B. ein Text (ledStateMsg) mit einem Status (ledState) an die Funktion übergeben werden.
String ledStateMsg = "LED State = "; ledStateMsg += ledState; TelnetMsg(ledStateMsg);
Ihr könnt natürlich auch die einfache Variante wählen und die Funktion direkt aufrufen.
TelnetMsg("Dies ist ein Test");
Sketch
Ihr müsst im Sketch mindestens die folgenden Zeilen anpassen damit auch eine WLAN Verbindung aufgebaut wird! Die IP Adresse findet ihr dann im Serial Monitor oder auf dem DHCP Server / Router.
const char* ssid = "SSID"; const char* password = "PASSWORD";
Im Sketch ist das bereits bekannte Over The Air Update und der Wifi Telnet Server mit allem was dazugehört enthalten. Zum Test habe ich noch eine LED Blink Funktion mit Telnet Ausgabe eingebaut. Der Wifi Telnet Server funktioniert natürlich auch ohne die Over The Air Update Funktion! Der Sketch ist so aber eine gute Grundlage für ein Projekt mit einem ESP8266 Modul.
In diesem Sketch geht es nur um die Ausgabe auf dem Telnet Client. Eingaben imTelnet Client werden aktuell nur auf der seriellen Konsole ausgegeben und nicht weiter verarbeitet.
#include <ESP8266WiFi.h> #include <ESP8266mDNS.h> #include <WiFiUdp.h> #include <ArduinoOTA.h> const char* ssid = "SSID"; const char* password = "PASSWORD"; uint8_t i; bool ConnectionEstablished; // Flag for successfully handled connection #define MAX_TELNET_CLIENTS 2 WiFiServer TelnetServer(23); WiFiClient TelnetClient[MAX_TELNET_CLIENTS]; void setup() { Serial.begin(115200); Serial.println("Over The Air and Telnet Example"); Serial.printf("Sketch size: %u\n", ESP.getSketchSize()); Serial.printf("Free size: %u\n", ESP.getFreeSketchSpace()); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); // ... Give ESP 10 seconds to connect to station. unsigned long startTime = millis(); Serial.print("Waiting for wireless connection "); while (WiFi.status() != WL_CONNECTED && millis() - startTime < 10000) { delay(200); Serial.print("."); } Serial.println(); while (WiFi.status() != WL_CONNECTED) { Serial.println("Connection Failed! Rebooting..."); delay(3000); ESP.restart(); } Serial.print("IP address: "); Serial.println(WiFi.localIP()); Serial.println("Starting Telnet server"); TelnetServer.begin(); TelnetServer.setNoDelay(true); pinMode(BUILTIN_LED, OUTPUT); // initialize onboard LED as output // OTA // Port defaults to 8266 // ArduinoOTA.setPort(8266); // Hostname defaults to esp8266-[ChipID] // ArduinoOTA.setHostname("myesp8266"); // No authentication by default ArduinoOTA.setPassword((const char *)"1234"); ArduinoOTA.onStart([]() { Serial.println("Start"); }); ArduinoOTA.onEnd([]() { Serial.println("\nEnd"); }); ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { Serial.printf("Progress: %u%%\r", (progress / (total / 100))); }); 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"); }); ArduinoOTA.begin(); } void loop() { ArduinoOTA.handle(); // Wait for OTA connection blinkLED(); // Blink LED Telnet(); // Handle telnet connections } void TelnetMsg(String text) { for(i = 0; i < MAX_TELNET_CLIENTS; i++) { if (TelnetClient[i] || TelnetClient[i].connected()) { TelnetClient[i].println(text); } } delay(10); // to avoid strange characters left in buffer } void Telnet() { // Cleanup disconnected session for(i = 0; i < MAX_TELNET_CLIENTS; i++) { if (TelnetClient[i] && !TelnetClient[i].connected()) { Serial.print("Client disconnected ... terminate session "); Serial.println(i+1); TelnetClient[i].stop(); } } // Check new client connections if (TelnetServer.hasClient()) { ConnectionEstablished = false; // Set to false for(i = 0; i < MAX_TELNET_CLIENTS; i++) { // Serial.print("Checking telnet session "); Serial.println(i+1); // find free socket if (!TelnetClient[i]) { TelnetClient[i] = TelnetServer.available(); Serial.print("New Telnet client connected to session "); Serial.println(i+1); TelnetClient[i].flush(); // clear input buffer, else you get strange characters TelnetClient[i].println("Welcome!"); TelnetClient[i].print("Millis since start: "); TelnetClient[i].println(millis()); TelnetClient[i].print("Free Heap RAM: "); TelnetClient[i].println(ESP.getFreeHeap()); TelnetClient[i].println("----------------------------------------------------------------"); ConnectionEstablished = true; break; } else { // Serial.println("Session is in use"); } } if (ConnectionEstablished == false) { Serial.println("No free sessions ... drop connection"); TelnetServer.available().stop(); // TelnetMsg("An other user cannot connect ... MAX_TELNET_CLIENTS limit is reached!"); } } for(i = 0; i < MAX_TELNET_CLIENTS; i++) { if (TelnetClient[i] && TelnetClient[i].connected()) { if(TelnetClient[i].available()) { //get data from the telnet client while(TelnetClient[i].available()) { Serial.write(TelnetClient[i].read()); } } } } } //////////////////////////////////////////////////////////////////////////////////////// // Blink function with telnet output const long interval = 2000; int ledState = LOW; unsigned long previousMillis = 0; void blinkLED() { unsigned long currentMillis = millis(); // if enough millis have elapsed if (currentMillis - previousMillis >= interval) { previousMillis = currentMillis; // toggle the LED ledState = !ledState; digitalWrite(BUILTIN_LED, ledState); String ledStateMsg = "LED State = "; ledStateMsg += ledState; TelnetMsg(ledStateMsg); } }
Hallo,
das mit dem Telnet- Server ist soweit klar und funktioniert auch. Was passiert aber mit den Meldungen aus z.B. ArduinoOTA.onError? die benötigen doch aber trotzdem eine serielle Verbindung, oder? Aber die ist bei der OTA- Übertragung nicht vorhanden.
Mein Ziel war den Status während der OTA- Übertragung anzusehen, da der esp8266 öfters mal nach der Übertragung hängt. Dann hilft nur noch ein flashen via USB.
Gruß, Klaus
Hallo Klaus,
das klappt nicht bzw. ich weiß leider nicht wie! Ich habe es versucht, aber sobald das OTA Update anfängt ist Telnet nicht mehr nutzbar.
Viele Grüße
Stefan
Hallo zusammen,
der OTA Prozess stoppt alle UDF Prozesse und somit auch alle TCP/IP Verbindungen. Ich würde empfehlen die Meldungen in einer Datei mithilfe von LittleFS zu speichern und nach dem Neustart zu übertragen. Das geht mit einem einfachen Webserver, mit dem die Datei heruntergeladen werden kann.
Viele Grüße,
Ladi
Hallo Kalus,
habe hier ein captive portas (AZ-Vertrieb), das sowohl AP als auch STA sein kann.
AP und STA haben natürlich verschiedene IP Adressen.
Über die WLAN Sta ist der Telnet server erreichbar.
Wie kann ich es anstellen, daß er über beide Wege / IPs erreichbar ist ?
Hallo,
tolle Idee. So habe ich jetzt in meinem Projekt es geschafft Meldung zum Handy(APP. Mobile Telnet) zu schicken.
Danke.