Dieses Tutorial beschreibt den Aufbau eines Pingcheck-Moduls, mit dem sich die Verfügbarkeit von Geräten im WLAN anzeigen lässt. Es sendet periodisch Pings an Geräte im Netzwerk. Wenn es eine Antwort erhält, leuchtet eine LED.
Wozu das ganze?!
Ganz einfach. Die Lampe leuchtet so lange, wie ein Rechner an ist. Wenn man ins Bett gehen will, und vergisst alle Rechner herunter zu fahren, fällt es dadurch auf.
# | Bezeichnung | ~Preis |
1 | ESP-01 Modul mit 512KB Speicher | 3,00 € |
1 | Kondensator 0,47 uF (Elko) | 0,05 € |
1 | Kondensator 1000 uF (Elko) | 0,45 € |
1 | Kondensator 0,1 uF (Elko) | 0,05 € |
1 | Transistor BC546 | 0,05 € |
1 | Widerstand 100 Ohm | 0,02 € |
1 | Widerstand 100K Ohm | 0,02 € |
2 | Widerstand 10K Ohm | 0,02 € |
1 | Spannungswandler L78L34 | 0,25 € |
1 | Helle LED | 0,30 € |
1 | USB-Kabel | 0,10 € |
Stiftleisten für ESP "Sockel" | 0,10 € | |
Gehäuse | ||
optional einen 5mm Plexiglas Stab | ||
< 5 € |
Bezeichnung |
Breadboard und Steckverbinder oder Lötkolben und (Lochraster-)platine |
USB-Seriell Wandler (zum Programmieren des ESP), siehe hier. |
Netzteil 5V DC oder eine andere "Stromquelle" mit USB (z.B. einen Router) |
optional: Heißluftfön |
optional: Minibohrer |
Das fertige Modul sieht so aus:
- Als erstes müsst ihr euch Gedanken darüber machen, in was für eine Hülle ihr das Modul bauen wollt. Ich habe aus optischen Gründen ein rundes Plastikgehäuse genommen.
-
Nun programmiert den ESP-01 mit dem folgenden Code:
/* ESP8266 Pingcheck Wifi Module Pings three IP Addresses. If one of them responses, the light is on. 2016 www.frag-duino.de */ #include <ESP8266WiFi.h> #include <WiFiClient.h> #include <ESP8266WebServer.h> #include <EEPROM.h> extern "C" { #include "user_interface.h" #include "ping.h" } ESP8266WebServer server(80); /* * To set the new Wifi, enter credentials in the two variables and set RESET_EEPROM to true. * During the next start it will save it into the EEPROM. * Then set RESET_EEPROM to false and flash it again. * When wifi changes, remember to first change the name over the webinterface. */ #define RESET_EEPROM false #define WIFI_SSID "bla" #define WIFI_PASSWORD "321" // Settings const int PING_INTERVAL = 5000; const int PIN_LED = 2; const int count_hosts = 3; int connection_try = 15; char host1[15]; char host2[15]; char host3[15]; boolean host_is_online[] = {false, false, false}; // EEPROM Addresses const int ADDRESS_IP1 = 0; const int ADDRESS_IP2 = 15; const int ADDRESS_IP3 = 30; const int ADDRESS_INIT = 105; // - 99 const int ADDRESS_PASSWORD = 45; // - 75 const int ADDRESS_SSID = 75; // - 105 const int EEPROM_SIZE = 106; // Variables IPAddress network_ip; char network_ssid[30]; char network_password[30]; struct ping_option pingopt; unsigned long last_ping = 0; unsigned long last_seen_online = 0; unsigned long currentMillis = 0; int currentHost = 0; int state_LED = LOW; boolean got_new_hosts; boolean save_wifi; // Save the current config void writeIPtoEEPROM() { for (int i = 0; i < 15; i++) { EEPROM.write(ADDRESS_IP1 + i, host1[i]); EEPROM.write(ADDRESS_IP2 + i, host2[i]); EEPROM.write(ADDRESS_IP3 + i, host3[i]); } EEPROM.commit(); } void writeSSIDtoEEPROM(String new_ssid) { for (int i = 0; i < 30; i++) { if (i < new_ssid.length()) EEPROM.write(ADDRESS_SSID + i, new_ssid[i]); else EEPROM.write(ADDRESS_SSID + i, '\0'); } EEPROM.commit(); } void writePASSWORDtoEEPROM(String new_password) { for (int i = 0; i < 30; i++) { if (i < new_password.length()) EEPROM.write(ADDRESS_PASSWORD + i, new_password[i]); else EEPROM.write(ADDRESS_PASSWORD + i, '\0'); } EEPROM.commit(); } // Reply is called, when response arrives static void callback_reply (void* arg, void *pdata) { struct ping_resp *pingresp = (struct ping_resp *)pdata; if (pingresp->resp_time > 0) { Serial.println(" Response"); last_seen_online = currentMillis; host_is_online[currentHost] = true; } else { Serial.println(" Timeout"); host_is_online[currentHost] = false; } } // Sends an echo request to an IP-Address void ping(uint32 ip) { pingopt.ip = ip; pingopt.count = 1; pingopt.coarse_time = 200; pingopt.recv_function = &callback_reply; // pingopt.sent_function = NULL; ping_start(&pingopt); } boolean checkIPsyntax(String ip) { // Only 0-9 and dots for (int i = 0; i <= 33; i++) if (ip.indexOf(i) != -1) return false; if (ip.indexOf(0x2F) != -1) return false; for (int i = 0x3A; i <= 0x7F; i++) if (ip.indexOf(i) != -1) return false; // Count the amount of dots int dots = 0; for (int i = 0; i < ip.length(); i++) if (ip[i] == '.') dots++; if (dots != 3) return false; // Check the range of the oktets int dot_1 = ip.indexOf('.'); int dot_2 = ip.indexOf('.', dot_1 + 1); int dot_3 = ip.indexOf('.', dot_2 + 1); int oktet_1 = ip.substring(0, dot_1).toInt(); int oktet_2 = ip.substring(dot_1 + 1, dot_2).toInt(); int oktet_3 = ip.substring(dot_2 + 1, dot_3).toInt(); int oktet_4 = ip.substring(dot_3 + 1).toInt(); if (oktet_1 >= 0 && oktet_1 <= 255 && oktet_2 >= 0 && oktet_2 <= 255 && oktet_3 >= 0 && oktet_3 <= 255 && oktet_4 >= 0 && oktet_4 <= 255 ) return true; else return false; } void handleRoot() { Serial.print(currentMillis); Serial.print(": HTTP-Request with "); got_new_hosts = false; save_wifi = false; String temp_ssid; String temp_password; if (server.args() > 0) { Serial.print(server.args()); Serial.print(" args: "); for (int a = 0; a < server.args(); a++) { Serial.print("["); Serial.print(server.argName(a)); Serial.print("="); Serial.print(server.arg(a)); Serial.print("]"); if (server.arg(a) == "Restart") // Restart ESP8266 system_restart(); else if (server.arg(a) == "Save-Wifi") { Serial.println("OK, Save-Wifi"); save_wifi = true; } else if (server.argName(a) == "ssid") { for (int i = 0; i < 30; i++) { if (i < server.arg(a).length()) network_ssid[i] = server.arg(a)[i]; else network_ssid[i] = '\0'; } } else if (server.argName(a) == "password") { for (int i = 0; i < 30; i++) { if (i < server.arg(a).length()) network_password[i] = server.arg(a)[i]; else network_password[i] = '\0'; } } else if (server.argName(a) == "ip1" && checkIPsyntax(server.arg(a))) { memset(host1, 0, sizeof(host1)); for (int i = 0; i < server.arg(a).length(); i++) host1[i] = server.arg(a)[i]; got_new_hosts = true; Serial.print(" OK1 "); } else if (server.argName(a) == "ip2" && checkIPsyntax(server.arg(a))) { memset(host2, 0, sizeof(host2)); for (int i = 0; i < server.arg(a).length(); i++) host2[i] = server.arg(a)[i]; got_new_hosts = true; Serial.print(" OK2 "); } else if (server.argName(a) == "ip3" && checkIPsyntax(server.arg(a))) { memset(host3, 0, sizeof(host3)); for (int i = 0; i < server.arg(a).length(); i++) host3[i] = server.arg(a)[i]; got_new_hosts = true; Serial.print(" OK3 "); } else Serial.print(" NACK; "); } } else Serial.print("no args"); Serial.println("."); // Save it if (got_new_hosts) writeIPtoEEPROM(); if (save_wifi) { writeSSIDtoEEPROM(network_ssid); if (temp_password != "notchanged") writePASSWORDtoEEPROM(network_password); } // Print the HTML-Page String result = "<html><head><title>PingCheck</title></head>\r\n<body>\r\n"; result += "PingCheck 2.0 (2015 Marcel Imig <a href=\"http://www.frag-duino.de\">www.frag-duino.de</a>)<br><br>\r\n\r\n"; result += "<fieldset name=\"wifistatus\"><legend>Wifi status</legend><form action=\"\" method=\"post\">"; result += "<table>\r\n"; result += "<tr><td><b>Network SSID:</b></td>\r\n"; result += "<td><input type=\"text\" name=\"ssid\" value=\""; result += network_ssid; result += "\" maxlength=\"30\"></td>\r\n</tr>\r\n"; result += "<tr><td><b>Network Password:</b></td>\r\n"; result += "<td><input type=\"password\" name=\"password\" value=\"notchanged\" maxlength=\"30\"></td>\r\n</tr>\r\n"; result += "</td>\r\n</tr>\r\n</table>\r\n"; result += "<input type=\"Submit\" name=\"send\" value=\"Save-Wifi\" >\r\n"; result += "<input type=\"Submit\" name=\"send\" value=\"Restart\" ></form></fieldset>\r\n\r\n<br>\r\n<br>\r\n"; result += "<fieldset name=\"hosts\"><legend>Hosts</legend>\r\n<b>Monitoring IPs:</b><br><br>\r\n\r\n"; result += "<form action=\"\" method=\"post\">"; result += "IP1: <input type=\"text\" name=\"ip1\" value=\""; result += host1; result += "\" "; if (host_is_online[0]) result += "style=\"background-color:green\""; else result += "style=\"background-color:red\""; result += " maxlength=\"15\"><br>\r\n"; result += "IP2: <input type=\"text\" name=\"ip2\" value=\""; result += host2; result += "\" "; if (host_is_online[1]) result += "style=\"background-color:green\""; else result += "style=\"background-color:red\""; result += " maxlength=\"15\"><br>\r\n"; result += "IP3: <input type=\"text\" name=\"ip3\" value=\""; result += host3; result += "\" "; if (host_is_online[2]) result += "style=\"background-color:green\""; else result += "style=\"background-color:red\""; result += " maxlength=\"15\"><br>\r\n"; result += "<input type=\"Submit\" name=\"send\" value=\"Save\"> \r\n"; result += "<input type=\"Submit\" name=\"send\" value=\"Refresh\">\r\n\r\n</form>\r\n"; result += "</body>\r\n</html>"; server.send(200, "text / html", result); } void handleDump() { Serial.println("EEPROM:"); for (int i = 0; i < EEPROM_SIZE; i++) { Serial.print(i); Serial.print(": "); Serial.println((char) EEPROM.read(i)); } Serial.println("END"); server.send(200, "text / html", "DUMPED ON SERIAL OUTPUT"); } void setup() { // Initialize Serial and LEDs Serial.begin(115200); delay(20); Serial.println("\r\n Ready "); pinMode(PIN_LED, OUTPUT); digitalWrite(PIN_LED, HIGH); // Read IPs and Wifi-credentials from EEPROM EEPROM.begin(EEPROM_SIZE); if (RESET_EEPROM) { // First start, initialize EEPROM strncpy(host1, "192.168.0.1", 11); strncpy(host2, "0.0.0.0", 7); strncpy(host3, "0.0.0.0", 7); writeSSIDtoEEPROM(WIFI_SSID); writePASSWORDtoEEPROM(WIFI_PASSWORD); writeIPtoEEPROM(); Serial.println("EEPROM initialized"); while (true) { digitalWrite(PIN_LED, HIGH); delay(100); digitalWrite(PIN_LED, LOW); delay(100); } } else { // Read from EEPROM for (int i = 0; i < 15; i++) { host1[i] = EEPROM.read(ADDRESS_IP1 + i); host2[i] = EEPROM.read(ADDRESS_IP2 + i); host3[i] = EEPROM.read(ADDRESS_IP3 + i); } for (int i = 0; i < 30; i++) // SSID network_ssid[i] = EEPROM.read(ADDRESS_SSID + i); for (int i = 0; i < 30; i++) // Password network_password[i] = EEPROM.read(ADDRESS_PASSWORD + i); } // Print hosts Serial.println("Hosts from EEPROM:"); Serial.print("[1]: "); Serial.println(host1); Serial.print("[2]: "); Serial.println(host2); Serial.print("[3]: "); Serial.println(host3); Serial.print("Wifi from EEPROM: \""); Serial.print(network_ssid); Serial.print("\" \""); Serial.print(network_password); Serial.println("\"\r\n"); // Connect to AP WiFi.mode(WIFI_STA); // Set to client WiFi.begin(network_ssid, network_password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.println("."); if (state_LED == HIGH) state_LED = LOW; else state_LED = HIGH; digitalWrite(PIN_LED, state_LED); } Serial.print("Connected to "); Serial.println(network_ssid); Serial.print("IP address: "); network_ip = WiFi.localIP(); Serial.println(network_ip); // Start the server server.on("/", handleRoot); server.on("/dump/", handleDump); server.begin(); digitalWrite(PIN_LED, HIGH); delay(250); digitalWrite(PIN_LED, LOW); } void loop() { server.handleClient(); currentMillis = millis(); // Read current runtime if (WiFi.status() != WL_CONNECTED) { Serial.println("Not connected anymore, restarting"); system_restart(); } if (last_ping + PING_INTERVAL < currentMillis) { Serial.print(currentMillis); const char* host; currentHost = (currentHost + 1) % count_hosts; if (currentHost == 0) host = host1; else if (currentHost == 1) host = host2; else host = host3; uint32 address = ipaddr_addr(host); if (host[0] == '0' && host[2] == '0' && host[4] == '0' && host[6] == '0') Serial.println(": Skipping"); else { Serial.print(": Pinging \""); Serial.print(host); Serial.print("\" - "); ping(address); last_ping = currentMillis; } } if (last_seen_online + (count_hosts * PING_INTERVAL) > currentMillis) state_LED = HIGH; else state_LED = LOW; digitalWrite(PIN_LED, state_LED); }
-
Baut nun die folgende Schaltung auf:
-
Um dem Modul einen stabilen Standfuß zu geben, habe ich dicke Muttern auf der Basisplatte aufgeklebt:
-
Um das ganze zu befestigen, habe ich es auf einer Metallplatte mit einem Kabelbinder befestigt und diese an einem Schrank festgeschraubt:
-
Wenn man dann ein Loch in den Deckel bohrt, kann man dort eine Acrylstange durchstecken:
Um sie zu biegen, benötigt man einen Heißluftfön. Dabei muss man darauf achten, dass man den Strahl nichtzu lange auf dieselbe Stelle richtet. In diesem Fall kommt es nämlich zu Blasenbildung. -
Die Konfiguration erfolgt über das Webinterface. Dort kann man angeben, welche Hosts zu überwachen sind:
-
Das Modul ist so rubust programmiert, dass es bei Verlust der WLAN-Verbindung neustartet und die Verbindung wiederherstellt.
Kommentare
Super und danke.
Würde mich über eine kleine Hilfe freuen.
Habe den ESP8266 ESP-12.
Wie kann ich jeder IP einen anderen GPIO("LED") zuordnen?
Gruß,
Marko
klar geht das. Aber nicht mit dem Code oben ;)
Spontan fallen mir zwei Wege ein um das zu lösen:
1. Du hast ja die Variable currentHost. Du kannst ein Array an Pins definieren, welches so groß ist wie die Anzahl der Hosts. Dann lässt du die entsprechende LED aufleuchten.
2. Du analysierst das ECHO_REPLY Paket (Die Antwort vom Ping). Dort müsste die Source IP stehen vom den Host der geantwortet hat. Das ist etwas sicherer, aber komplizierter.
Klaus-Dieter Brinkmann
Die beiden Dateien sind Teil der Arduino Libraries für den ESP8266. Da stimmt also etwas mit der Konfiguration deiner Arduino IDE nicht.