diff options
| author | schneefux <schneefux+commit@schneefux.xyz> | 2015-12-25 13:38:31 +0100 |
|---|---|---|
| committer | schneefux <schneefux+commit@schneefux.xyz> | 2015-12-25 13:38:31 +0100 |
| commit | 76edd6c448c55c4f9bcf37509ec372149c966993 (patch) | |
| tree | c4eed3c1ecb40987cbe2b77df47b2e6e23c71494 /portal.cpp | |
| download | weather-snowman-76edd6c448c55c4f9bcf37509ec372149c966993.tar.gz weather-snowman-76edd6c448c55c4f9bcf37509ec372149c966993.zip | |
first commit
Diffstat (limited to 'portal.cpp')
| -rw-r--r-- | portal.cpp | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/portal.cpp b/portal.cpp new file mode 100644 index 0000000..5013249 --- /dev/null +++ b/portal.cpp @@ -0,0 +1,275 @@ +#include "portal.h" + +//#define DEBUG + +#define NONE -1 +#define BLINK -2 +#define FADEIN -3 +#define FADEOUT -4 + +const IPAddress apIP(192, 168, 1, 1); +const char* apSSID; + +boolean isAPactive; +String scanSSIDList; + +int apiOverrides[4] = {NONE, NONE, NONE, NONE}; +boolean requestLedUpdate = false; + +DNSServer dnsServer; +ESP8266WebServer webServer(80); + +#define ICONPATH "http://openweathermap.org/img/w/" +String weatherIcon = ""; + +void portalSetup(String ssid) { + apSSID = ssid.c_str(); + + WiFi.hostname(ssid); + // connect to configured network or fallback to setup AP + if (!enterClientMode(NULL, NULL)) { + enterAPMode(); // let the user enter the credentials + } + startWebServer(); +} + +void portalLoop() { + if (isAPactive) { + dnsServer.processNextRequest(); + } + webServer.handleClient(); +} + +boolean isConnected() { + return !isAPactive; +} + +void startWebServer() { +#ifdef DEBUG + Serial.print(F("Starting Web Server at ")); + Serial.print(WiFi.softAPIP()); Serial.print(" "); Serial.println(WiFi.localIP()); +#endif + + webServer.on("/settings", []() { + String s = "<h1>WLAN-Einstellungen</h1><p>Bitte wähle deinen Accesspoint und gib das Passwort ein.</p>"; + s += "<form method=\"get\" action=\"setap\"><label>SSID: </label><select name=\"ssid\">"; + s += scanSSIDList; + s += "</select><br>Passwort: <input name=\"pass\" length=64 type=\"password\"><input type=\"submit\"></form>"; + webServer.send(200, "text/html", makePage("WLAN-Einstellungen", s)); + }); + + webServer.on("/setap", []() { + String ssid = urlDecode(webServer.arg("ssid")); +#ifdef DEBUG + Serial.print(F("Connecting to: ")); Serial.println(ssid); +#endif + String pass = urlDecode(webServer.arg("pass")); + + String s = "<h1>Einrichtung abgeschlossen.</h1><p>Das Gerät wird zu \""; + s += ssid; + s += "\" verbunden."; + webServer.send(200, "text/html", makePage("WLAN-Einstellungen", s)); + + if (!enterClientMode(ssid.c_str(), pass.c_str())) { + enterAPMode(); // wrong passphrase + } + }); + + webServer.on("/reset", []() { + String s = "<h1>Zurückgesetzt</h1><p>Zum Einstellen bitte mit dem Accesspoint \"Snowman\" verbinden.</p>"; + webServer.send(200, "text/html", makePage("Zurücksetzen", s)); + enterAPMode(); + }); + + webServer.on("/api", []() { + String response = ""; + + for (int n = 0; n < webServer.args(); n++) { + String sArgName = webServer.argName(n); + + if (sArgName.startsWith("led")) { + String sPinNumber = sArgName.substring(3); + if (sPinNumber == "") { + String msg = "API: Invalid argument '" + sArgName + "' - pin number invalid\n"; + response += msg; +#ifdef DEBUG + Serial.print(msg); +#endif + continue; + } + int pinNumber = sPinNumber.toInt(); + if (pinNumber < 0 || pinNumber > 3) { + String msg = "API: Invalid argument '" + sArgName + "' - pin number out of range\n"; + response += msg; +#ifdef DEBUG + Serial.print(msg); +#endif + continue; + } + + String sArg = webServer.arg(n); + int val = -1; + if (sArg == "fade" || sArg == "fadein") { + val = FADEIN; + } else if (sArg == "fadeout") { + val = FADEOUT; + } else if (sArg == "blink") { + val = BLINK; + } else if (sArg == "clear") { + val = NONE; + } else { + val = sArg.toInt(); + } + + if ((val != FADEIN && val != FADEOUT && val != BLINK && val != NONE && val < 0) || val > PWMRANGE) { + String msg = "API: Value out of range for argument '" + sArgName + "': '" + String(val) + "'\n"; + response += msg; +#ifdef DEBUG + Serial.print(msg); +#endif + continue; + } + String msg = "API: Overriding pin " + String(pinNumber) + " to " + String(val) + "\n"; + response += msg; +#ifdef DEBUG + Serial.print(msg); +#endif + apiOverrides[pinNumber] = val; + requestLedUpdate = true; + } + if (webServer.argName(n) == "clear") { + if (webServer.arg(n) == "true") { + for (int j = 0; j < 4; j++) { + apiOverrides[j] = NONE; + } + } + String msg = "API: Cleared pin overrides\n"; + response += msg; +#ifdef DEBUG + Serial.print(msg); +#endif + requestLedUpdate = true; + } + } + + webServer.send(200, "text/html", makePage("API", "<pre>" + response + "</pre>")); + }); + + webServer.on("/", []() { + String s = "<h1>Snowman</h1><p><a href=\"/reset\">Einstellungen zurücksetzen</a></p>"; + s += "<p><a href=\"/settings\">Einstellungen ändern</a></p>"; + s += "<p><img src=\"" ICONPATH + weatherIcon + ".png\" /></p>"; + webServer.send(200, "text/html", makePage("Snowman", s)); + }); + + webServer.onNotFound([]() { + String redirect = "http://" + ipToStr(apIP) + "/settings"; + webServer.send(200, "text/html", makeRedirectPage(redirect, 2)); + }); + + webServer.begin(); +} + +int getAPIOverride(int pin) { + return apiOverrides[pin]; +} + +boolean apiNeedLedUpdate() { + return requestLedUpdate; +} + +void apiUpdatedLeds() { + requestLedUpdate = false; +} + +void setWeatherIcon(String id) { + weatherIcon = id; +} + +// must enter AP mode after scanning (SSID & PW get lost) +void scanSSIDs() { +#ifdef DEBUG + Serial.println(F("Scanning networks")); +#endif + + WiFi.disconnect(); + WiFi.mode(WIFI_STA); + delay(100); + + int n = WiFi.scanNetworks(); + delay(100); + scanSSIDList = ""; + for (int i = 0; i < n; ++i) { + scanSSIDList += "<option value=\""; + scanSSIDList += WiFi.SSID(i); // FIXME XSS attack possible? + scanSSIDList += "\">"; + scanSSIDList += WiFi.SSID(i); + scanSSIDList += "</option>"; + } + +#ifdef DEBUG + Serial.println(F("Finished scanning")); +#endif +} + + +// also read https://github.com/esp8266/Arduino/issues/529 + +// sets up an AP for the user to enter his/her WiFi credentials +void enterAPMode() { +#ifdef DEBUG + Serial.println(F("Entering AP mode")); +#endif + + scanSSIDs(); + + // create ad hoc setup-network + WiFi.disconnect(); + WiFi.mode(WIFI_AP); + isAPactive = true; + delay(100); + WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); + WiFi.softAP(apSSID); +#ifdef DEBUG + Serial.println(F("Started Access Point")); +#endif + + dnsServer.start(apIP); +} + +// returns true if successfully connected to the last AP +boolean enterClientMode(const char* ssid, const char *passphrase) { + dnsServer.stop(); + + if (ssid && strlen(ssid) > 0) { // if ssid is not given, try to connect to the memorized AP + WiFi.disconnect(); + WiFi.begin(ssid, passphrase); // register credentials + } + WiFi.mode(WIFI_STA); + isAPactive = false; + delay(100); + + // SSID and password are memorized until WiFi.begin() + // https://github.com/esp8266/Arduino/issues/244 + int count = 0; +#ifdef DEBUG + Serial.print(F("Waiting for Wi-Fi connection to ")); Serial.println(WiFi.SSID()); +#endif + while (count++ < 30) { // attempt for about 30 * 1/2 = 15 seconds + if (WiFi.status() == WL_CONNECTED) { +#ifdef DEBUG + Serial.println(); Serial.println(F("Connected!")); +#endif + return true; + } + delay(500); +#ifdef DEBUG + Serial.print("."); +#endif + } +#ifdef DEBUG + Serial.println(); Serial.println(F("Not connected")); +#endif + return false; +} + |
