From eea34ed8ceacf64cb2de2945b74f3a4b9670ec90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xose=20P=C3=A9rez?= Date: Sat, 13 Aug 2016 03:36:05 +0200 Subject: [PATCH] Moved Wifi management code to a library --- code/lib/JustWifi/JustWifi.cpp | 200 ++++++++++++++++++++++++++++++ code/lib/JustWifi/JustWifi.h | 99 +++++++++++++++ code/src/main.cpp | 216 ++++++++++++++++----------------- 3 files changed, 404 insertions(+), 111 deletions(-) create mode 100644 code/lib/JustWifi/JustWifi.cpp create mode 100644 code/lib/JustWifi/JustWifi.h diff --git a/code/lib/JustWifi/JustWifi.cpp b/code/lib/JustWifi/JustWifi.cpp new file mode 100644 index 00000000..8833fb2b --- /dev/null +++ b/code/lib/JustWifi/JustWifi.cpp @@ -0,0 +1,200 @@ +/* + +JustWifi + +Wifi Manager for ESP8266 + +Copyright (C) 2016 by Xose Pérez + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +#include "JustWifi.h" +#include + +bool JustWifi::connected() { + return (WiFi.status() == WL_CONNECTED); +} + +bool JustWifi::autoConnect() { + + // Return if already connected + if (connected()) return true; + + // Try to connect to last successful network + WiFi.mode(WIFI_STA); + if (WiFi.SSID()) { + + _doCallback(MESSAGE_AUTO_CONNECTING, (char *) WiFi.SSID().c_str()); + ETS_UART_INTR_DISABLE(); + wifi_station_disconnect(); + ETS_UART_INTR_ENABLE(); + WiFi.begin(); + + if (WiFi.status() == WL_CONNECTED) { + _mode = MODE_STATION; + _doCallback(MESSAGE_CONNECTED); + return true; + } + + _doCallback(MESSAGE_AUTO_FAILED); + + } else { + + _doCallback(MESSAGE_AUTO_NOSSID); + + } + + _mode = MODE_NONE; + return false; + +} + +bool JustWifi::connect() { + + unsigned long timeout; + + // Return if already connected + if (connected()) return true; + + // Loop through configured networks + for (unsigned char i=0; i<_network_count; i++) { + + // TODO: Static IP options here + + // Connect + _doCallback(MESSAGE_CONNECTING, (char *) _network[i].ssid.c_str()); + WiFi.begin(_network[i].ssid.c_str(), _network[i].pass.c_str()); + + // Check connection with timeout + timeout = millis(); + while (millis() - timeout < _connect_timeout) { + _doCallback(MESSAGE_CONNECT_WAITING); + if (WiFi.status() == WL_CONNECTED) break; + delay(100); + } + + // Get out of the i loop if connected + if (WiFi.status() == WL_CONNECTED) { + break; + } else { + _mode = MODE_NONE; + _doCallback(MESSAGE_CONNECT_FAILED, (char *) _network[i].ssid.c_str()); + } + + } + + if (WiFi.status() == WL_CONNECTED) { + //WiFi.setAutoConnect(true); + //WiFi.setAutoReconnect(true); + _mode = MODE_STATION; + _doCallback(MESSAGE_CONNECTED); + return true; + } + + return false; + +} + +bool JustWifi::startAP(char * ssid, char * pass) { + + // Return if already connected + // if (connected()) return true; + + // TODO: Static IP options here + + _doCallback(MESSAGE_ACCESSPOINT_CREATING); + WiFi.mode(WIFI_AP); + if (strlen(pass) > 0) { + if (strlen(pass) < 8 || strlen(pass) > 63) { + _mode = MODE_NONE; + _doCallback(MESSAGE_ACCESSPOINT_FAILED); + return false; + } + WiFi.softAP(ssid, pass); + } else { + WiFi.softAP(ssid); + } + + // TODO: Setup the DNS server redirecting all the queries to this IP + + _ssid = String(ssid); + _mode = MODE_ACCESS_POINT; + _doCallback(MESSAGE_ACCESSPOINT_CREATED); + + return true; + +} + +bool JustWifi::disconnect() { + WiFi.disconnect(true); + _mode = MODE_NONE; + _doCallback(MESSAGE_DISCONNECTED); +} + +bool JustWifi::cleanNetworks() { + _network_count = 0; +} + +bool JustWifi::addNetwork(char * ssid, char * pass) { + if (_network_count == MAX_NETWORKS) return false; + _network[_network_count].ssid = String(ssid); + _network[_network_count].pass = String(pass); + _network_count++; + return true; +} + +justwifi_mode_t JustWifi::getMode() { + return _mode; +} + +String JustWifi::getIP() { + if (_mode == MODE_STATION) { + return WiFi.localIP().toString(); + } else if (_mode == MODE_ACCESS_POINT) { + return WiFi.softAPIP().toString(); + } + return String(""); +} + +String JustWifi::getNetwork() { + if (_mode == MODE_STATION) { + return WiFi.SSID(); + } + return _ssid; +} + +void JustWifi::setConnectTimeout(unsigned long ms) { + _connect_timeout = ms; +} + +void JustWifi::onMessage(TMessageFunction fn) { + _callback = fn; +} + +void JustWifi::loop() { + if ((WiFi.status() != WL_CONNECTED) && (_mode == MODE_STATION)) { + _mode = MODE_NONE; + _doCallback(MESSAGE_DISCONNECTED); + } + if ((WiFi.status() == WL_CONNECTED) && (_mode != MODE_STATION)) { + _mode = MODE_STATION; + _doCallback(MESSAGE_CONNECTED); + } +} + +void JustWifi::_doCallback(justwifi_messages_t message, char * parameter) { + if (_callback != NULL) _callback(message, parameter); +} diff --git a/code/lib/JustWifi/JustWifi.h b/code/lib/JustWifi/JustWifi.h new file mode 100644 index 00000000..985254c9 --- /dev/null +++ b/code/lib/JustWifi/JustWifi.h @@ -0,0 +1,99 @@ +/* + +JustWifi + +Wifi Manager for ESP8266 + +Copyright (C) 2016 by Xose Pérez + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +#ifndef JustWifi_h +#define JustWifi_h + +#include +#include + +extern "C" { + #include "user_interface.h" +} + +#define MAX_NETWORKS 3 +#define WIFI_CONNECT_TIMEOUT 10000 + +struct network_t { + String ssid; + String pass; +}; + +typedef enum { + MODE_NONE, + MODE_STATION, + MODE_ACCESS_POINT +} justwifi_mode_t; + +typedef enum { + MESSAGE_AUTO_NOSSID, + MESSAGE_AUTO_CONNECTING, + MESSAGE_AUTO_FAILED, + MESSAGE_CONNECTING, + MESSAGE_CONNECT_WAITING, + MESSAGE_CONNECT_FAILED, + MESSAGE_CONNECTED, + MESSAGE_ACCESSPOINT_CREATING, + MESSAGE_ACCESSPOINT_FAILED, + MESSAGE_ACCESSPOINT_CREATED, + MESSAGE_DISCONNECTED +} justwifi_messages_t; + +class JustWifi { + + public: + + typedef std::function TMessageFunction; + + bool autoConnect(); + bool connect(); + bool startAP(char * ssid, char * pass); + bool disconnect(); + bool connected(); + + bool cleanNetworks(); + bool addNetwork(char * ssid, char * pass); + + void setConnectTimeout(unsigned long ms); + + justwifi_mode_t getMode(); + String getIP(); + String getNetwork(); + + void onMessage(TMessageFunction fn); + void loop(); + + private: + + network_t _network[MAX_NETWORKS]; + String _ssid; + justwifi_mode_t _mode = MODE_NONE; + unsigned char _network_count = 0; + unsigned long _connect_timeout = WIFI_CONNECT_TIMEOUT; + TMessageFunction _callback = NULL; + + void _doCallback(justwifi_messages_t message, char * parameter = NULL); + +}; + +#endif diff --git a/code/src/main.cpp b/code/src/main.cpp index 6e7f7314..f43c34d9 100644 --- a/code/src/main.cpp +++ b/code/src/main.cpp @@ -31,6 +31,7 @@ along with this program. If not, see . #include "Config.h" #include "NoFUSSClient.h" +#include "JustWifi.h" #include #include @@ -66,6 +67,10 @@ extern "C" { #define ENABLE_RF 0 #define ENABLE_DHT 0 +#define BUTTON_PIN 0 +#define RELAY_PIN 12 +#define LED_PIN 13 + #ifdef ESPURNA #define MANUFACTURER "TINKERMAN" #define DEVICE "ESPURNA" @@ -89,12 +94,10 @@ extern "C" { #ifdef NODEMCUV2 #define MANUFACTURER "NODEMCU" #define DEVICE "LOLIN" + #undef LED_PIN + #define LED_PIN 16 #endif -#define BUTTON_PIN 0 -#define RELAY_PIN 12 -#define LED_PIN 13 - #define ADMIN_PASS "fibonacci" #define BUFFER_SIZE 1024 #define STATUS_UPDATE_INTERVAL 10000 @@ -120,12 +123,6 @@ extern "C" { #define MQTT_TEMPERATURE_TOPIC "/temperature" #define MQTT_HUMIDITY_TOPIC "/humidity" -#define WIFI_CONNECT_TIMEOUT 10000 -#define WIFI_RECONNECT_DELAY 2000 -#define WIFI_STATUS_CONNECTING 0 -#define WIFI_STATUS_CONNECTED 1 -#define WIFI_STATUS_AP 2 - #define CURRENT_PIN 0 #define ADC_BITS 10 #define REFERENCE_VOLTAGE 1.0 @@ -139,8 +136,7 @@ extern "C" { // Globals // ----------------------------------------------------------------------------- -byte status = WIFI_STATUS_CONNECTING; - +JustWifi jw; DebounceEvent button1 = false; #if ENABLE_WEBSERVER @@ -227,7 +223,7 @@ void blink(unsigned long delayOff, unsigned long delayOn) { } void showStatus() { - if (WiFi.status() == WL_CONNECTED) { + if (jw.connected()) { blink(5000, 500); } else { blink(500, 500); @@ -424,128 +420,126 @@ void toggleRelay() { // Wifi // ----------------------------------------------------------------------------- -void wifiSetupAP() { +void wifiSetup() { - // Set WIFI module AP mode - WiFi.mode(WIFI_AP); - #ifdef DEBUG - WiFi.printDiag(Serial); - #endif + // Message callbacks + jw.onMessage([](justwifi_messages_t code, char * parameter) { - // SoftAP mode - WiFi.softAP(config.hostname.c_str(), ADMIN_PASS); - status = WIFI_STATUS_AP; - delay(100); - #ifdef DEBUG - Serial.print(F("[WIFI] ACCESS POINT Mode, SSID: ")); - Serial.print(config.hostname); - Serial.print(F(", Password: \"")); - Serial.print(ADMIN_PASS); - Serial.print(F("\", IP address: ")); - Serial.println(WiFi.softAPIP()); - #endif - -} - -void wifiSetupSTA() { - - byte network = 0; - - // Set WIFI module to STA mode - WiFi.mode(WIFI_STA); - #ifdef DEBUG - //WiFi.printDiag(Serial); - #endif + if (code == MESSAGE_CONNECTED) { + #if ENABLE_NOFUSS + NoFUSSClient.handle(); + #endif + } else { + #if ENABLE_MQTT + if (mqtt.connected()) mqtt.disconnect(); + #endif + } - #if ENABLE_MQTT - if (mqtt.connected()) mqtt.disconnect(); - #endif + #if ENABLE_RF + if (code == MESSAGE_CONNECTING) { + RemoteReceiver::disable(); + } else if (code != MESSAGE_CONNECT_WAITING) { + RemoteReceiver::enable(); + } + #endif - #if ENABLE_RF - RemoteReceiver::disable(); - #endif + if (code == MESSAGE_CONNECT_WAITING) { + showStatus(); + } - while (network < 3) { + #ifdef DEBUG - if (config.ssid[network].length() > 0) { + if (code == MESSAGE_AUTO_NOSSID) { + Serial.println("[WIFI] No information about the last successful network"); + } - WiFi.begin( - (const char *) config.ssid[network].c_str(), - (const char *) config.pass[network].c_str() - ); + if (code == MESSAGE_AUTO_CONNECTING) { + Serial.print("[WIFI] Connecting to last successful network: "); + Serial.println(parameter); + } - #ifdef DEBUG - Serial.print(F("[WIFI] Connecting to ")); - Serial.println(config.ssid[network]); - #endif + if (code == MESSAGE_AUTO_FAILED) { + Serial.println("[WIFI] Could not connect to last successful network"); + } - // Wait - unsigned long timeout = millis() + WIFI_CONNECT_TIMEOUT; - while (timeout > millis()) { - showStatus(); - if (WiFi.status() == WL_CONNECTED) break; - delay(100); + if (code == MESSAGE_CONNECTING) { + Serial.print("[WIFI] Connecting to "); + Serial.println(parameter); } - } + if (code == MESSAGE_CONNECT_WAITING) { + // + } - if (WiFi.status() == WL_CONNECTED) break; - network++; + if (code == MESSAGE_CONNECT_FAILED) { + Serial.print("[WIFI] Could not connect to "); + Serial.println(parameter); + } - } + if (code == MESSAGE_CONNECTED) { + Serial.print("[WIFI] Connected to "); + Serial.print(jw.getNetwork()); + Serial.print(" with IP "); + Serial.println(jw.getIP()); + } - #if ENABLE_RF - RemoteReceiver::enable(); - #endif + if (code == MESSAGE_DISCONNECTED) { + Serial.println("[WIFI] Disconnected"); + } - if (WiFi.status() == WL_CONNECTED) { + if (code == MESSAGE_ACCESSPOINT_CREATING) { + Serial.println("[WIFI] Creating access point"); + } - WiFi.setAutoConnect(true); - status = WIFI_STATUS_CONNECTED; + if (code == MESSAGE_ACCESSPOINT_CREATED) { + Serial.print("[WIFI] Access point created with SSID "); + Serial.print(jw.getNetwork()); + Serial.print(" and IP "); + Serial.println(jw.getIP()); + } - #ifdef DEBUG - Serial.print(F("[WIFI] STATION Mode, SSID: ")); - Serial.print(WiFi.SSID()); - Serial.print(F(", IP address: ")); - Serial.println(WiFi.localIP()); - #endif + if (code == MESSAGE_ACCESSPOINT_FAILED) { + Serial.println("[WIFI] Could not create access point"); + } - #if ENABLE_NOFUSS - NoFUSSClient.handle(); #endif - } else { - - #ifdef DEBUG - Serial.println(F("[WIFI] Not connected")); - #endif + }); - } } -void wifiSetup(bool force) { - if (force || (WiFi.status() != WL_CONNECTED)) { - wifiSetupSTA(); - if (WiFi.status() != WL_CONNECTED) wifiSetupAP(); - } +bool wifiAP() { + //jw.disconnect(); + return jw.startAP((char *) config.hostname.c_str(), (char *) ADMIN_PASS); } void wifiLoop() { - static unsigned long last_check = 0; + jw.loop(); // Check disconnection - if ((status == WIFI_STATUS_CONNECTED) && (WiFi.status() != WL_CONNECTED)) { - status = WIFI_STATUS_CONNECTING; - } + if ((!jw.connected()) && (jw.getMode() != MODE_ACCESS_POINT)) { - // If not connected (either AP or STA) try to reconnect every WIFI_RECONNECT_DELAY - if (status == WIFI_STATUS_CONNECTING) { - if ((millis() - last_check) > WIFI_RECONNECT_DELAY) { - wifiSetup(false); - last_check = millis(); + WiFi.printDiag(Serial); + + // Set networks + jw.cleanNetworks(); + jw.addNetwork((char *) config.ssid[0].c_str(), (char *) config.pass[0].c_str()); + jw.addNetwork((char *) config.ssid[1].c_str(), (char *) config.pass[1].c_str()); + jw.addNetwork((char *) config.ssid[2].c_str(), (char *) config.pass[2].c_str()); + + // Connecting + if (!jw.autoConnect()) { + if (!jw.connect()) { + if (!wifiAP()) { + #ifdef DEBUG + Serial.println("[WIFI] Could not start any wifi interface!"); + #endif + } + } } + } } @@ -801,7 +795,9 @@ void wifiLoop() { #if ENABLE_POWER power.setCurrentRatio(config.pwCurrentRatio.toFloat()); #endif - wifiSetup(true); + + // Disconnect from current WIFI network, wifiLoop will take care of the reconnection + jw.disconnect(); } @@ -1145,7 +1141,7 @@ void hardwareLoop() { if (button1.loop()) { if (button1.getEvent() == EVENT_SINGLE_CLICK) toggleRelay(); - if (button1.getEvent() == EVENT_LONG_CLICK) wifiSetupAP(); + if (button1.getEvent() == EVENT_LONG_CLICK) wifiAP(); if (button1.getEvent() == EVENT_DOUBLE_CLICK) ESP.reset(); } @@ -1185,12 +1181,12 @@ void welcome() { Serial.println(getIdentifier()); Serial.print(F("Last reset reason: ")); Serial.println(ESP.getResetReason()); - Serial.print(F("Free heap: ")); - Serial.print(ESP.getFreeHeap()); - Serial.println(F(" bytes")); Serial.print(F("Memory size: ")); Serial.print(ESP.getFlashChipSize()); Serial.println(F(" bytes")); + Serial.print(F("Free heap: ")); + Serial.print(ESP.getFreeHeap()); + Serial.println(F(" bytes")); FSInfo fs_info; if (SPIFFS.info(fs_info)) { Serial.print(F("File system total size: ")); @@ -1216,9 +1212,7 @@ void setup() { // configuration interface config.hostname = getIdentifier(); wifi_station_set_hostname((char *) config.hostname.c_str()); - - // I am handling first connection in the loop - //wifiSetup(false); + wifiSetup(); #if ENABLE_OTA OTASetup();