diff --git a/GitOTA.cpp b/GitOTA.cpp index 4560ea9..49ea3c5 100644 --- a/GitOTA.cpp +++ b/GitOTA.cpp @@ -252,6 +252,7 @@ void GitRepo::toJSON(JsonResponse &json) { #define ERR_DOWNLOAD_CONNECTION -42 void GitUpdater::loop() { + if(!net.connected()) return; if(this->status == GIT_STATUS_READY) { if(settings.checkForUpdate && (millis() > net.connectTime + 60000) && // Wait a minute before checking after connection. diff --git a/MQTT.cpp b/MQTT.cpp index e24c144..af87378 100644 --- a/MQTT.cpp +++ b/MQTT.cpp @@ -35,8 +35,11 @@ void MQTTClass::reset() { this->connect(); } bool MQTTClass::loop() { - if(settings.MQTT.enabled && !rebootDelay.reboot && !this->suspended && !mqttClient.connected()) - this->connect(); + if(settings.MQTT.enabled && !rebootDelay.reboot && !this->suspended && !mqttClient.connected()) { + esp_task_wdt_reset(); + if(!net.connected()) this->connect(); + } + esp_task_wdt_reset(); if(settings.MQTT.enabled) mqttClient.loop(); return true; } diff --git a/Network.cpp b/Network.cpp index 937c6f7..a9b3846 100644 --- a/Network.cpp +++ b/Network.cpp @@ -34,7 +34,9 @@ bool Network::setup() { WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN); WiFi.setSortMethod(WIFI_CONNECT_AP_BY_SIGNAL); WiFi.persistent(false); + WiFi.setAutoReconnect(false); WiFi.onEvent(this->networkEvent); + this->disconnectTime = millis(); if(WiFi.status() == WL_CONNECTED) WiFi.disconnect(true, true); if(settings.connType == conn_types_t::wifi || settings.connType == conn_types_t::unset) { WiFi.persistent(false); @@ -42,7 +44,6 @@ bool Network::setup() { Serial.print("WiFi Mode: "); Serial.println(WiFi.getMode()); WiFi.mode(WIFI_STA); - //settings.WIFI.printNetworks(); } sockEmit.begin(); return true; @@ -50,13 +51,14 @@ bool Network::setup() { conn_types_t Network::preferredConnType() { switch(settings.connType) { case conn_types_t::wifi: + return settings.WIFI.ssid[0] != '\0' ? conn_types_t::wifi : conn_types_t::ap; case conn_types_t::unset: case conn_types_t::ap: - return strlen(settings.WIFI.ssid) > 0 ? conn_types_t::wifi : conn_types_t::ap; + return conn_types_t::ap; case conn_types_t::ethernetpref: - return strlen(settings.WIFI.ssid) > 0 && !ETH.linkUp() ? conn_types_t::wifi : conn_types_t::ethernet; + return settings.WIFI.ssid[0] != '\0' && (!ETH.linkUp() && this->ethStarted) ? conn_types_t::wifi : conn_types_t::ethernet; case conn_types_t::ethernet: - return ETH.linkUp() ? conn_types_t::ethernet : conn_types_t::ap; + return ETH.linkUp() || !this->ethStarted ? conn_types_t::ethernet : conn_types_t::ap; default: return settings.connType; } @@ -77,51 +79,62 @@ void Network::loop() { // b. WiFi: Perform synchronous scan for APs related to the SSID. If the SSID can be found then perform // the connection process for the WiFi connection. // c. SoftAP: This condition retains the Soft AP because no other connection method is available. - - this->connect(); // Connection timeout handled in connect function as well as the opening of the Soft AP if needed. - if(this->connecting()) return; // If we are currently attempting to connect to something then we need to bail here. conn_types_t ctype = this->preferredConnType(); - if(this->softAPOpened && WiFi.softAPgetStationNum() == 0) { - // If the Soft AP is opened and there are no clients connected then we need to scan for an AP. If - // our target exists we will exit out of the Soft AP and start that connection. - if(ctype == conn_types_t::wifi) { - // Scan for an AP. - if(!_apScanning && WiFi.scanNetworks(true, false, true, 300, 0, settings.WIFI.ssid) == -1) { - _apScanning = true; - } - } - } - else if(this->connected() && ctype == conn_types_t::wifi && settings.WIFI.roaming) { - // Periodically look for an AP. - if(millis() > SSID_SCAN_INTERVAL + this->lastWifiScan) { - //Serial.println("Started scan for access points"); - if(!_apScanning && WiFi.scanNetworks(true, false, true, 300, 0, settings.WIFI.ssid) == -1) { - _apScanning = true; - this->lastWifiScan = millis(); - } - } - } + this->connect(ctype); // Connection timeout handled in connect function as well as the opening of the Soft AP if needed. + if(this->connecting()) return; // If we are currently attempting to connect to something then we need to bail here. if(_apScanning) { - if(!settings.WIFI.roaming || settings.connType != conn_types_t::wifi || (this->softAPOpened && WiFi.softAPgetStationNum() != 0)) _apScanning = false; + if((this->connected() && !settings.WIFI.roaming) || // We are already connected and should not be roaming. + (this->softAPOpened && WiFi.softAPgetStationNum() != 0) || // The Soft AP is open and a user is connected. + (ctype != conn_types_t::wifi)) { // The Ethernet link is up so we should ignore this scan. + Serial.println("Cancelling WiFi STA Scan..."); + _apScanning = false; + WiFi.scanDelete(); + } else { - uint16_t n = WiFi.scanComplete(); - if( n > 0) { + int16_t n = WiFi.scanComplete(); + if( n >= 0) { // If the scan is complete but the WiFi isn't ready this can return 0. uint8_t bssid[6]; int32_t channel = 0; if(this->getStrongestAP(settings.WIFI.ssid, bssid, &channel)) { if(!WiFi.BSSID() || memcmp(bssid, WiFi.BSSID(), sizeof(bssid)) != 0) { - Serial.printf("Found stronger AP %d %02X:%02X:%02X:%02X:%02X:%02X\n", channel, bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]); - if(this->softAPOpened) { - WiFi.softAPdisconnect(true); - WiFi.mode(WIFI_STA); + if(!this->connected()) { + Serial.printf("Connecting to AP %02X:%02X:%02X:%02X:%02X:%02X CH: %d\n", bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5], channel); + this->connectWiFi(bssid, channel); + } + else { + Serial.printf("Found stronger AP %02X:%02X:%02X:%02X:%02X:%02X CH: %d\n", bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5], channel); + this->changeAP(bssid, channel); } - this->changeAP(bssid, channel); } } _apScanning = false; } } } + if(!this->connecting()) { + if((this->softAPOpened && WiFi.softAPgetStationNum() == 0) || + (!this->connected() && ctype == conn_types_t::wifi)) { + // If the Soft AP is opened and there are no clients connected then we need to scan for an AP. If + // our target exists we will exit out of the Soft AP and start that connection. We are also + // going to continuously scan when there is no connection and our preferred connection is wifi. + if(ctype == conn_types_t::wifi) { + // Scan for an AP but only if we are not already scanning. + if(!_apScanning && WiFi.scanNetworks(true, false, true, 300, 0, settings.WIFI.ssid) == -1) { + _apScanning = true; + } + } + } + else if(this->connected() && ctype == conn_types_t::wifi && settings.WIFI.roaming) { + // Periodically look for a roaming AP. + if(millis() > SSID_SCAN_INTERVAL + this->lastWifiScan) { + //Serial.println("Started scan for access points"); + if(!_apScanning && WiFi.scanNetworks(true, false, true, 300, 0, settings.WIFI.ssid) == -1) { + _apScanning = true; + this->lastWifiScan = millis(); + } + } + } + } if(millis() - this->lastEmit > 1500) { // Post our connection status if needed. this->lastEmit = millis(); @@ -131,14 +144,14 @@ void Network::loop() { } esp_task_wdt_reset(); // Make sure we do not reboot here. } + sockEmit.loop(); mqtt.loop(); - if(settings.ssdpBroadcast) { + if(settings.ssdpBroadcast && this->connected()) { if(!SSDP.isStarted) SSDP.begin(); if(SSDP.isStarted) SSDP.loop(); } else if(!settings.ssdpBroadcast && SSDP.isStarted) SSDP.end(); - /* // --------------------------- @@ -215,6 +228,9 @@ bool Network::changeAP(const uint8_t *bssid, const int32_t channel) { mqtt.disconnect(); //sockEmit.end(); WiFi.disconnect(false, true); + this->connType = conn_types_t::unset; + this->_connecting = true; + this->connectStart = millis(); WiFi.begin(settings.WIFI.ssid, settings.WIFI.passphrase, channel, bssid); this->connectStart = millis(); return false; @@ -299,9 +315,11 @@ void Network::emitSockets(uint8_t num) { this->emitHeap(num); } void Network::setConnected(conn_types_t connType) { + esp_task_wdt_reset(); this->connType = connType; this->connectTime = millis(); connectRetries = 0; + Serial.println("Setting connected..."); if(this->connType == conn_types_t::wifi) { if(this->softAPOpened && WiFi.softAPgetStationNum() == 0) { WiFi.softAPdisconnect(true); @@ -326,6 +344,8 @@ void Network::setConnected(conn_types_t connType) { } // NET: Begin this in the startup. //sockEmit.begin(); + esp_task_wdt_reset(); + if(this->connectAttempts == 1) { Serial.println(); if(this->connType == conn_types_t::wifi) { @@ -358,6 +378,7 @@ void Network::setConnected(conn_types_t connType) { settings.IP.dns1 = ETH.dnsIP(0); settings.IP.dns2 = ETH.dnsIP(1); } + esp_task_wdt_reset(); JsonSockEvent *json = sockEmit.beginEmit("ethernet"); json->beginObject(); json->addElem("connected", this->connected()); @@ -365,6 +386,7 @@ void Network::setConnected(conn_types_t connType) { json->addElem("fullduplex", ETH.fullDuplex()); json->endObject(); sockEmit.endEmit(); + esp_task_wdt_reset(); } } else { @@ -415,6 +437,7 @@ void Network::setConnected(conn_types_t connType) { SSDP.setManufacturerURL(0, "https://github.com/rstrouse"); SSDP.setURL(0, "/"); SSDP.setActive(0, true); + esp_task_wdt_reset(); if(MDNS.begin(settings.hostname)) { Serial.printf("MDNS Responder Started: serverId=%s\n", settings.serverId); MDNS.addService("http", "tcp", 80); @@ -427,9 +450,11 @@ void Network::setConnected(conn_types_t connType) { MDNS.addServiceTxt("espsomfy_rts", "tcp", "version", String(settings.fwVersion.name)); } if(settings.ssdpBroadcast) { + esp_task_wdt_reset(); SSDP.begin(); } else if(SSDP.isStarted) SSDP.end(); + esp_task_wdt_reset(); this->emitSockets(); settings.printAvailHeap(); this->needsBroadcast = true; @@ -509,7 +534,7 @@ void Network::updateHostname() { } } } -bool Network::connectWiFi() { +bool Network::connectWiFi(const uint8_t *bssid, const int32_t channel) { if(this->softAPOpened && WiFi.softAPgetStationNum() > 0) { // There is a client connected to the soft AP. We do not want to close out the connection. While both the // Soft AP and a wifi connection can coexist on ESP32 the performance is abysmal. @@ -518,11 +543,34 @@ bool Network::connectWiFi() { this->connType = conn_types_t::unset; return true; } - - if(settings.WIFI.ssid[0] != '\0') { + WiFi.setSleep(false); + if(!settings.IP.dhcp) { + if(!WiFi.config(settings.IP.ip, settings.IP.gateway, settings.IP.subnet, settings.IP.dns1, settings.IP.dns2)) + WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE); + } + else + WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE); + if(settings.hostname[0] != '\0') WiFi.setHostname(settings.hostname); + delay(100); + + if(bssid && channel > 0) { + if(WiFi.status() == WL_CONNECTED && WiFi.SSID().compareTo(settings.WIFI.ssid) == 0 + && WiFi.channel() == channel) { + this->disconnected = 0; + return true; + } + this->connTarget = conn_types_t::wifi; + this->connType = conn_types_t::unset; + Serial.println("WiFi begin..."); + this->_connecting = true; + WiFi.begin(settings.WIFI.ssid, settings.WIFI.passphrase, channel, bssid); + this->connectStart = millis(); + } + else if(settings.WIFI.ssid[0] != '\0') { if(WiFi.status() == WL_CONNECTED && WiFi.SSID().compareTo(settings.WIFI.ssid) == 0) { // If we are connected to the target SSID then just return. this->disconnected = 0; + this->_connecting = true; return true; } if(this->_connecting) return true; @@ -539,14 +587,6 @@ bool Network::connectWiFi() { Serial.println("dbm) "); } else Serial.println("Connecting to AP"); - WiFi.setSleep(false); - WiFi.disconnect(false); - if(!settings.IP.dhcp) { - if(!WiFi.config(settings.IP.ip, settings.IP.gateway, settings.IP.subnet, settings.IP.dns1, settings.IP.dns2)) - WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE); - } - else - WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE); delay(100); // There is also another method simply called hostname() but this is legacy for esp8266. if(settings.hostname[0] != '\0') WiFi.setHostname(settings.hostname); @@ -554,11 +594,11 @@ bool Network::connectWiFi() { Serial.println(WiFi.getHostname()); WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN); WiFi.setSortMethod(WIFI_CONNECT_AP_BY_SIGNAL); - uint8_t bssid[6]; - int32_t channel = 0; - if(this->getStrongestAP(settings.WIFI.ssid, bssid, &channel)) { - Serial.printf("Found strongest AP %d %02X:%02X:%02X:%02X:%02X:%02X\n", channel, bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]); - WiFi.begin(settings.WIFI.ssid, settings.WIFI.passphrase, channel, bssid); + uint8_t _bssid[6]; + int32_t _channel = 0; + if(this->getStrongestAP(settings.WIFI.ssid, _bssid, &_channel)) { + Serial.printf("Found strongest AP %02X:%02X:%02X:%02X:%02X:%02X CH:%d\n", _bssid[0], _bssid[1], _bssid[2], _bssid[3], _bssid[4], _bssid[5], _channel); + WiFi.begin(settings.WIFI.ssid, settings.WIFI.passphrase, _channel, _bssid); } else WiFi.begin(settings.WIFI.ssid, settings.WIFI.passphrase); @@ -566,8 +606,30 @@ bool Network::connectWiFi() { this->connectStart = millis(); return true; } -bool Network::connect() { +bool Network::connect(conn_types_t ctype) { esp_task_wdt_reset(); + if(this->connecting()) return true; + if(this->disconnectTime == 0) this->disconnectTime = millis(); + if(ctype == conn_types_t::ethernet && this->connType != conn_types_t::ethernet) { + // Here we need to call the connect to ethernet. + this->connectWired(); + } + else if(ctype == conn_types_t::ap || (!this->connected() && millis() > this->disconnectTime + CONNECT_TIMEOUT)) { + if(!this->softAPOpened && !this->openingSoftAP) { + this->disconnectTime = millis(); + this->openSoftAP(); + } + } + return true; + /* + if(this->connecting()) { + // If we are currently connecting it matters whether this is a wifi target or if it is an ethernet target. The preferred + // connection type make the determination for us. + + + + } + if(this->connecting()) { // CHECK FOR CONNECTION TIMEOUT // ------------------------------------- @@ -602,7 +664,7 @@ bool Network::connect() { else if(this->softAPOpened) { // If the Soft AP is currently open then we will let the passive scanning or Ethernet link layer // do its thing to connect or reconnect. - return false; + this->connType = conn_types_t::unset; } else if(settings.connType == conn_types_t::ethernet || settings.connType == conn_types_t::ethernetpref) this->connectWired(); @@ -617,7 +679,9 @@ bool Network::connect() { WiFi.softAPdisconnect(true); if(this->connType == conn_types_t::wifi) WiFi.mode(WIFI_STA); } + if(this->connecting() && millis() > this->connectStart + CONNECT_TIMEOUT + 100) this->_connecting = false; return true; + */ } uint32_t Network::getChipId() { uint32_t chipId = 0; @@ -633,9 +697,10 @@ bool Network::getStrongestAP(const char *ssid, uint8_t *bssid, int32_t *channel) int32_t chan = -1; memset(bssid, 0x00, 6); esp_task_wdt_delete(NULL); - uint8_t n = this->connected() ? WiFi.scanComplete() : WiFi.scanNetworks(false, false, false, 300, 0, ssid); + int16_t n = WiFi.scanComplete(); + //int16_t n = this->connected() ? WiFi.scanComplete() : WiFi.scanNetworks(false, false, false, 300, 0, ssid); esp_task_wdt_add(NULL); - for(uint8_t i = 0; i < n; i++) { + for(int16_t i = 0; i < n; i++) { if(WiFi.SSID(i).compareTo(ssid) == 0) { if(WiFi.RSSI(i) > strength) { strength = WiFi.RSSI(i); @@ -649,13 +714,12 @@ bool Network::getStrongestAP(const char *ssid, uint8_t *bssid, int32_t *channel) } bool Network::openSoftAP() { if(this->softAPOpened || this->openingSoftAP) return true; - WiFi.disconnect(false); + if(this->connected()) WiFi.disconnect(false); this->openingSoftAP = true; Serial.println(); Serial.println("Turning the HotSpot On"); esp_task_wdt_reset(); // Make sure we do not reboot here. WiFi.softAP(strlen(settings.hostname) > 0 ? settings.hostname : "ESPSomfy RTS", ""); - Serial.println("Initializing AP for credentials modification"); delay(200); return true; } @@ -668,11 +732,13 @@ bool Network::connected() { return false; } bool Network::connecting() { return this->_connecting; } +void Network::clearConnecting() { this->_connecting = false; } void Network::networkEvent(WiFiEvent_t event) { switch(event) { case ARDUINO_EVENT_WIFI_READY: Serial.println("(evt) WiFi interface ready"); break; case ARDUINO_EVENT_WIFI_SCAN_DONE: - Serial.println("(evt) Completed scan for access points"); + Serial.printf("(evt) Completed scan for access points (%d)\n", WiFi.scanComplete()); + //Serial.println("(evt) Completed scan for access points"); net.lastWifiScan = millis(); break; case ARDUINO_EVENT_WIFI_STA_START: @@ -680,14 +746,20 @@ void Network::networkEvent(WiFiEvent_t event) { if(settings.hostname[0] != '\0') WiFi.setHostname(settings.hostname); break; case ARDUINO_EVENT_WIFI_STA_STOP: Serial.println("(evt) WiFi clients stopped"); break; - case ARDUINO_EVENT_WIFI_STA_CONNECTED: Serial.println("(evt) Connected to access point"); break; - case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: Serial.println("(evt) Disconnected from WiFi access point"); break; - case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE: Serial.println("(evt) Authentication mode of access point has changed"); break; + case ARDUINO_EVENT_WIFI_STA_CONNECTED: Serial.println("(evt) Connected to WiFi STA access point"); break; + case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: + Serial.printf("(evt) Disconnected from WiFi STA access point. Connecting: %d\n", net.connecting()); + net.connType = conn_types_t::unset; + net.disconnectTime = millis(); + net.clearConnecting(); + break; + case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE: Serial.println("(evt) Authentication mode of STA access point has changed"); break; case ARDUINO_EVENT_WIFI_STA_GOT_IP: - Serial.print("Got WiFi IP: "); + Serial.print("(evt) Got WiFi STA IP: "); Serial.println(WiFi.localIP()); net.connType = conn_types_t::wifi; net.connectTime = millis(); + net.setConnected(conn_types_t::wifi); break; case ARDUINO_EVENT_WIFI_STA_LOST_IP: Serial.println("Lost IP address and IP address is reset to 0"); break; case ARDUINO_EVENT_ETH_GOT_IP: @@ -703,7 +775,8 @@ void Network::networkEvent(WiFiEvent_t event) { settings.IP.gateway = ETH.gatewayIP(); settings.IP.dns1 = ETH.dnsIP(0); settings.IP.dns2 = ETH.dnsIP(1); - } + } + net.setConnected(conn_types_t::ethernet); break; case ARDUINO_EVENT_ETH_CONNECTED: Serial.print("(evt) Ethernet Connected "); @@ -711,6 +784,8 @@ void Network::networkEvent(WiFiEvent_t event) { case ARDUINO_EVENT_ETH_DISCONNECTED: Serial.println("(evt) Ethernet Disconnected"); net.connType = conn_types_t::unset; + net.disconnectTime = millis(); + net.clearConnecting(); break; case ARDUINO_EVENT_ETH_START: Serial.println("(evt) Ethernet Started"); @@ -729,7 +804,6 @@ void Network::networkEvent(WiFiEvent_t event) { break; case ARDUINO_EVENT_WIFI_AP_STOP: if(!net.openingSoftAP) Serial.println("(evt) WiFi SoftAP Stopped"); - //if(net.softAPOpened) net.openingSoftAP = false; net.softAPOpened = false; break; default: diff --git a/Network.h b/Network.h index 5345ce3..864966c 100644 --- a/Network.h +++ b/Network.h @@ -26,6 +26,7 @@ class Network { conn_types_t connTarget = conn_types_t::unset; bool connected(); bool connecting(); + void clearConnecting(); conn_types_t preferredConnType(); String ssid; String mac; @@ -33,11 +34,12 @@ class Network { int strength; int disconnected = 0; int connectAttempts = 0; + uint32_t disconnectTime = 0; uint32_t connectStart = 0; uint32_t connectTime = 0; bool openSoftAP(); - bool connect(); - bool connectWiFi(); + bool connect(conn_types_t ctype); + bool connectWiFi(const uint8_t *bssid = nullptr, const int32_t channel = -1); bool connectWired(); void setConnected(conn_types_t connType); bool getStrongestAP(const char *ssid, uint8_t *bssid, int32_t *channel); diff --git a/SSDP.cpp b/SSDP.cpp index 6f76a1f..f866865 100644 --- a/SSDP.cpp +++ b/SSDP.cpp @@ -161,7 +161,7 @@ void UPNPDeviceType::setChipId(uint32_t chipId) { (uint16_t)chipId & 0xff); } SSDPClass::SSDPClass():sendQueue{false, INADDR_NONE, 0, nullptr, false, 0, "", response_types_t::root} {} -SSDPClass::~SSDPClass() { end(); } +SSDPClass::~SSDPClass() { end(); this->isStarted = false; } bool SSDPClass::begin() { for(int i = 0; i < SSDP_QUEUE_SIZE; i++) { this->sendQueue[i].waiting = false; @@ -209,6 +209,7 @@ void SSDPClass::end() { if(this->_server.connected()) { this->_sendByeBye(); this->_server.close(); + Serial.println("Disconnected from SSDP..."); } this->isStarted = false; // Clear out the last notified so if the user starts us up again it will notify @@ -216,8 +217,6 @@ void SSDPClass::end() { for(uint8_t i = 0; i < this->m_cdeviceTypes; i++) { this->deviceTypes[i].lastNotified = 0; } - - Serial.println("Disconnected from SSDP..."); } UPNPDeviceType* SSDPClass::getDeviceType(uint8_t ndx) { if(ndx < this->m_cdeviceTypes) return &this->deviceTypes[ndx]; return nullptr; } UPNPDeviceType* SSDPClass::findDeviceByType(char *devType) { diff --git a/SomfyController.ino.esp32.bin b/SomfyController.ino.esp32.bin index 991e6cc..79d65de 100644 Binary files a/SomfyController.ino.esp32.bin and b/SomfyController.ino.esp32.bin differ diff --git a/SomfyController.ino.esp32s3.bin b/SomfyController.ino.esp32s3.bin index 0145167..fce66a2 100644 Binary files a/SomfyController.ino.esp32s3.bin and b/SomfyController.ino.esp32s3.bin differ