diff --git a/src/Config.h b/src/Config.h
index e302821..fd8bfc4 100644
--- a/src/Config.h
+++ b/src/Config.h
@@ -4,7 +4,7 @@
#define NUKI_HUB_VERSION "9.02"
#define NUKI_HUB_BUILD "unknownbuildnr"
-#define NUKI_HUB_DATE "unknowndate"
+#define NUKI_HUB_DATE "2024-10-18"
#define GITHUB_LATEST_RELEASE_URL (char*)"https://github.com/technyon/nuki_hub/releases/latest"
#define GITHUB_OTA_MANIFEST_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/manifest.json"
diff --git a/src/NukiNetwork.cpp b/src/NukiNetwork.cpp
index 529bcde..b8498bf 100644
--- a/src/NukiNetwork.cpp
+++ b/src/NukiNetwork.cpp
@@ -170,6 +170,11 @@ NetworkDevice *NukiNetwork::device()
return _device;
}
+bool NukiNetwork::isConnected()
+{
+ return _device->isConnected();
+}
+
#ifdef NUKI_HUB_UPDATER
void NukiNetwork::initialize()
{
@@ -427,7 +432,7 @@ bool NukiNetwork::update()
});
}
- if(_logIp && device()->isConnected() && !_device->localIP().equals("0.0.0.0"))
+ if(_logIp && _device->isConnected() && !_device->localIP().equals("0.0.0.0"))
{
_logIp = false;
Log->print(F("IP: "));
@@ -1083,11 +1088,12 @@ void NukiNetwork::publishHASSConfig(char* deviceType, const char* baseTopic, cha
baseTopic,
_lockPath + mqtt_topic_uptime,
deviceType,
- "",
+ "duration",
"",
"diagnostic",
"",
- { { (char*)"en", (char*)"true" }});
+ { { (char*)"en", (char*)"true" },
+ { (char*)"unit_of_meas", (char*)"min"}});
if(_preferences->getBool(preference_mqtt_log_enabled, false))
{
@@ -3906,9 +3912,4 @@ String NukiNetwork::localIP()
{
return _device->localIP();
}
-
-bool NukiNetwork::isConnected()
-{
- return _device->isConnected();
-}
#endif
\ No newline at end of file
diff --git a/src/NukiNetwork.h b/src/NukiNetwork.h
index 602d74b..79872d7 100644
--- a/src/NukiNetwork.h
+++ b/src/NukiNetwork.h
@@ -26,6 +26,7 @@ public:
void reconfigureDevice();
void scan(bool passive = false, bool async = true);
bool isApOpen();
+ bool isConnected();
void clearWifiFallback();
const String networkDeviceName() const;
@@ -44,7 +45,6 @@ public:
void disableAutoRestarts(); // disable on OTA start
void disableMqtt();
String localIP();
- bool isConnected();
void subscribe(const char* prefix, const char* path);
void initTopic(const char* prefix, const char* path, const char* value);
diff --git a/src/WebCfgServer.cpp b/src/WebCfgServer.cpp
index eb72821..ed4d76a 100644
--- a/src/WebCfgServer.cpp
+++ b/src/WebCfgServer.cpp
@@ -302,6 +302,28 @@ void WebCfgServer::initialize()
}
}
+void WebCfgServer::printCheckBox(PsychicStreamResponse *response, const char *token, const char *description, const bool value, const char *htmlClass)
+{
+ response->print("
| ");
+ response->print(description);
+ response->print(" | ");
+
+ response->print("print(token);
+ response->print("\" value=\"0\"");
+ response->print("/>");
+
+ response->print("print(token);
+
+ response->print("\" class=\"");
+ response->print(htmlClass);
+
+ response->print("\" value=\"1\"");
+ response->print(value ? " checked=\"checked\"" : "");
+ response->print("/> |
");
+}
+
#ifndef CONFIG_IDF_TARGET_ESP32H2
esp_err_t WebCfgServer::buildSSIDListHtml(PsychicRequest *request)
{
@@ -377,6 +399,14 @@ esp_err_t WebCfgServer::buildWifiConnectHtml(PsychicRequest *request)
printInputField(&response, "WIFISSID", "SSID", "", 32, "id=\"inputssid\"", false, true);
printInputField(&response, "WIFIPASS", "Secret key", "", 63, "id=\"inputpass\"", false, true);
response.print("");
+ response.print("IP Address assignment
");
+ response.print("");
+ printCheckBox(&response, "DHCPENA", "Enable DHCP", _preferences->getBool(preference_ip_dhcp_enabled), "");
+ printInputField(&response, "IPADDR", "Static IP address", _preferences->getString(preference_ip_address).c_str(), 15, "");
+ printInputField(&response, "IPSUB", "Subnet", _preferences->getString(preference_ip_subnet).c_str(), 15, "");
+ printInputField(&response, "IPGTW", "Default gateway", _preferences->getString(preference_ip_gateway).c_str(), 15, "");
+ printInputField(&response, "DNSSRV", "DNS Server", _preferences->getString(preference_ip_dns_server).c_str(), 15, "");
+ response.print("
");
response.print("
");
response.print("");
response.print("");
@@ -412,6 +442,41 @@ bool WebCfgServer::processWiFi(PsychicRequest *request, String& message)
{
pass = value;
}
+ else if(key == "DHCPENA")
+ {
+ if(_preferences->getBool(preference_ip_dhcp_enabled, true) != (value == "1"))
+ {
+ _preferences->putBool(preference_ip_dhcp_enabled, (value == "1"));
+ }
+ }
+ else if(key == "IPADDR")
+ {
+ if(_preferences->getString(preference_ip_address, "") != value)
+ {
+ _preferences->putString(preference_ip_address, value);
+ }
+ }
+ else if(key == "IPSUB")
+ {
+ if(_preferences->getString(preference_ip_subnet, "") != value)
+ {
+ _preferences->putString(preference_ip_subnet, value);
+ }
+ }
+ else if(key == "IPGTW")
+ {
+ if(_preferences->getString(preference_ip_gateway, "") != value)
+ {
+ _preferences->putString(preference_ip_gateway, value);
+ }
+ }
+ else if(key == "DNSSRV")
+ {
+ if(_preferences->getString(preference_ip_dns_server, "") != value)
+ {
+ _preferences->putString(preference_ip_dns_server, value);
+ }
+ }
}
ssid.trim();
@@ -419,55 +484,50 @@ bool WebCfgServer::processWiFi(PsychicRequest *request, String& message)
if (ssid.length() > 0 && pass.length() > 0)
{
+ if (_preferences->getBool(preference_ip_dhcp_enabled, true) && _preferences->getString(preference_ip_address, "").length() <= 0)
+ {
+ const IPConfiguration* _ipConfiguration = new IPConfiguration(_preferences);
+
+ if(!_ipConfiguration->dhcpEnabled())
+ {
+ WiFi.config(_ipConfiguration->ipAddress(), _ipConfiguration->dnsServer(), _ipConfiguration->defaultGateway(), _ipConfiguration->subnet());
+ }
+ }
+
WiFi.begin(ssid, pass);
int loop = 0;
- while(WiFi.status() != WL_CONNECTED && loop < 150)
+ while(!_network->isConnected() && loop < 150)
{
delay(100);
loop++;
}
- if (WiFi.status() != WL_CONNECTED)
+ if (!_network->isConnected())
{
message = "Failed to connect to the given SSID with the given secret key, credentials not saved
";
+ return res;
}
else
{
- message = "Connection successful. Rebooting Nuki Hub.
";
- if(WiFi.isConnected())
+ if(_network->isConnected())
{
- esp_wifi_disconnect();
+ message = "Connection successful. Rebooting Nuki Hub.
";
+ _preferences->putString(preference_wifi_ssid, ssid);
+ _preferences->putString(preference_wifi_pass, pass);
+ res = true;
}
-
- wifi_config_t wifi_cfg;
- if(esp_wifi_get_config(WIFI_IF_STA, &wifi_cfg) != ESP_OK) {
- Log->println("Failed to get Wi-Fi configuration in RAM");
+ else
+ {
+ message = "Failed to connect to the given SSID, no IP received, credentials not saved
";
return res;
}
-
- if (esp_wifi_set_storage(WIFI_STORAGE_FLASH) != ESP_OK) {
- Log->println("Failed to set storage Wi-Fi");
- return res;
- }
-
- memset(wifi_cfg.sta.ssid, 0, sizeof(wifi_cfg.sta.ssid));
- memset(wifi_cfg.sta.password, 0, sizeof(wifi_cfg.sta.password));
-
- if (esp_wifi_set_config(WIFI_IF_STA, &wifi_cfg) != ESP_OK) {
- Log->println("Failed to set Wi-Fi configuration");
- return res;
- }
-
- _preferences->putString(preference_wifi_ssid, ssid);
- _preferences->putString(preference_wifi_pass, pass);
-
- res = true;
}
}
else
{
message = "No SSID or secret key entered, credentials not saved
";
+ return res;
}
return res;
@@ -4213,28 +4273,6 @@ esp_err_t WebCfgServer::processFactoryReset(PsychicRequest *request)
return res;
}
-void WebCfgServer::printCheckBox(PsychicStreamResponse *response, const char *token, const char *description, const bool value, const char *htmlClass)
-{
- response->print("| ");
- response->print(description);
- response->print(" | ");
-
- response->print("print(token);
- response->print("\" value=\"0\"");
- response->print("/>");
-
- response->print("print(token);
-
- response->print("\" class=\"");
- response->print(htmlClass);
-
- response->print("\" value=\"1\"");
- response->print(value ? " checked=\"checked\"" : "");
- response->print("/> |
");
-}
-
void WebCfgServer::printTextarea(PsychicStreamResponse *response,
const char *token,
const char *description,
diff --git a/src/WebCfgServer.h b/src/WebCfgServer.h
index 0a6e75d..e9be8b9 100644
--- a/src/WebCfgServer.h
+++ b/src/WebCfgServer.h
@@ -67,7 +67,6 @@ private:
esp_err_t processUnpair(PsychicRequest *request, bool opener);
esp_err_t processUpdate(PsychicRequest *request);
esp_err_t processFactoryReset(PsychicRequest *request);
- void printCheckBox(PsychicStreamResponse *response, const char* token, const char* description, const bool value, const char* htmlClass);
void printTextarea(PsychicStreamResponse *response, const char *token, const char *description, const char *value, const size_t& maxLength, const bool& enabled = true, const bool& showLengthRestriction = false);
void printDropDown(PsychicStreamResponse *response, const char *token, const char *description, const String preselectedValue, std::vector> options, const String className);
void buildNavigationButton(PsychicStreamResponse *response, const char* caption, const char* targetPath, const char* labelText = "");
@@ -107,6 +106,7 @@ private:
void buildHtmlHeader(PsychicStreamResponse *response, String additionalHeader = "");
void waitAndProcess(const bool blocking, const uint32_t duration);
esp_err_t handleOtaUpload(PsychicRequest *request, const String& filename, uint64_t index, uint8_t *data, size_t len, bool final);
+ void printCheckBox(PsychicStreamResponse *response, const char* token, const char* description, const bool value, const char* htmlClass);
void printProgress(size_t prg, size_t sz);
#ifndef CONFIG_IDF_TARGET_ESP32H2
esp_err_t buildWifiConnectHtml(PsychicRequest *request);
diff --git a/src/networkDevices/WifiDevice.cpp b/src/networkDevices/WifiDevice.cpp
index 01e6e35..5c7e893 100644
--- a/src/networkDevices/WifiDevice.cpp
+++ b/src/networkDevices/WifiDevice.cpp
@@ -22,20 +22,24 @@ void WifiDevice::initialize()
String pass = _preferences->getString(preference_wifi_pass, "");
WiFi.setHostname(_hostname.c_str());
- if(!_ipConfiguration->dhcpEnabled())
- {
- WiFi.config(_ipConfiguration->ipAddress(), _ipConfiguration->dnsServer(), _ipConfiguration->defaultGateway(), _ipConfiguration->subnet());
- }
-
WiFi.onEvent([&](WiFiEvent_t event, WiFiEventInfo_t info)
{
- if(event == ARDUINO_EVENT_WIFI_STA_DISCONNECTED)
+ if(event == ARDUINO_EVENT_WIFI_STA_DISCONNECTED || event == ARDUINO_EVENT_WIFI_STA_STOP)
{
if(!_openAP && !_connecting && _connected)
{
onDisconnected();
+ _hasIP = false;
}
}
+ else if(event == ARDUINO_EVENT_WIFI_STA_GOT_IP)
+ {
+ _hasIP = true;
+ }
+ else if(event == ARDUINO_EVENT_WIFI_STA_LOST_IP)
+ {
+ _hasIP = false;
+ }
else if(event == ARDUINO_EVENT_WIFI_STA_CONNECTED)
{
onConnected();
@@ -117,10 +121,7 @@ void WifiDevice::initialize()
}
else
{
- Log->println("No SSID or Wifi password saved, opening AP");
- _connectOnScanDone = false;
- _openAP = true;
- scan(false, true);
+ restartEsp(RestartReason::ReconfigureWifi);
return;
}
}
@@ -158,23 +159,28 @@ void WifiDevice::initialize()
void WifiDevice::scan(bool passive, bool async)
{
- WiFi.scanDelete();
+ if(!_connecting)
+ {
+ WiFi.scanDelete();
+ WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN);
+ WiFi.setSortMethod(WIFI_CONNECT_AP_BY_SIGNAL);
- if(async)
- {
- Log->println(F("Wi-Fi async scan started"));
- }
- else
- {
- Log->println(F("Wi-Fi sync scan started"));
- }
- if(passive)
- {
- WiFi.scanNetworks(async,false,true,75U);
- }
- else
- {
- WiFi.scanNetworks(async);
+ if(async)
+ {
+ Log->println(F("Wi-Fi async scan started"));
+ }
+ else
+ {
+ Log->println(F("Wi-Fi sync scan started"));
+ }
+ if(passive)
+ {
+ WiFi.scanNetworks(async,false,true,75U);
+ }
+ else
+ {
+ WiFi.scanNetworks(async);
+ }
}
}
@@ -182,12 +188,9 @@ void WifiDevice::openAP()
{
if(_startAP)
{
- WiFi.persistent(false);
WiFi.mode(WIFI_AP_STA);
- WiFi.persistent(false);
WiFi.softAPsetHostname(_hostname.c_str());
WiFi.softAP("NukiHub", "NukiHubESP32");
- WiFi.persistent(false);
_startAP = false;
}
}
@@ -197,7 +200,6 @@ bool WifiDevice::connect()
bool ret = false;
String ssid = _preferences->getString(preference_wifi_ssid, "");
String pass = _preferences->getString(preference_wifi_pass, "");
- WiFi.persistent(false);
WiFi.mode(WIFI_STA);
WiFi.setHostname(_hostname.c_str());
delay(500);
@@ -239,99 +241,75 @@ bool WifiDevice::connect()
else
{
_connecting = true;
+ esp_wifi_scan_stop();
Log->println(String(F("Trying to connect to SSID ")) + ssid + String(F(" found with RSSI: ")) +
String(WiFi.RSSI(bestConnection)) + String(F("(")) +
String(constrain((100.0 + WiFi.RSSI(bestConnection)) * 2, 0, 100)) +
String(F(" %) and BSSID: ")) + WiFi.BSSIDstr(bestConnection) +
String(F(" and channel: ")) + String(WiFi.channel(bestConnection)));
- ret = WiFi.begin(ssid.c_str(), pass.c_str(), WiFi.channel(bestConnection), WiFi.BSSID(bestConnection), true);
- WiFi.persistent(false);
- _connecting = false;
- }
-
- if(!ret)
- {
- int loop = 0;
-
- while(!isConnected() && loop < 200)
+
+
+ if(!_ipConfiguration->dhcpEnabled())
{
- loop++;
- delay(100);
+ WiFi.config(_ipConfiguration->ipAddress(), _ipConfiguration->dnsServer(), _ipConfiguration->defaultGateway(), _ipConfiguration->subnet());
}
-
- if(!isConnected())
+
+ WiFi.begin(ssid, pass);
+ auto status = WiFi.waitForConnectResult(10000);
+
+ switch (status)
{
- esp_wifi_disconnect();
- esp_wifi_stop();
- esp_wifi_deinit();
-
- Log->println(F("Failed to connect. Wait for ESP restart."));
- delay(1000);
- restartEsp(RestartReason::WifiInitFailed);
+ case WL_CONNECTED:
+ Log->println("WiFi connected");
+ break;
+ case WL_NO_SSID_AVAIL:
+ Log->println("WiFi SSID not available");
+ break;
+ case WL_CONNECT_FAILED:
+ Log->println("WiFi connection failed");
+ break;
+ case WL_IDLE_STATUS:
+ Log->println("WiFi changing status");
+ break;
+ case WL_DISCONNECTED:
+ Log->println("WiFi disconnected");
+ break;
+ default:
+ Log->println("WiFi timeout");
+ break;
}
- }
- else
- {
- if(!_preferences->getBool(preference_wifi_converted, false))
- {
- _preferences->putBool(preference_wifi_converted, true);
- }
-
- int loop = 0;
-
- while(!isConnected() && loop < 200)
- {
- loop++;
- delay(100);
- }
-
- if(!isConnected())
+
+ if (status != WL_CONNECTED)
{
if(_preferences->getBool(preference_restart_on_disconnect, false) && ((esp_timer_get_time() / 1000) > 60000))
{
restartEsp(RestartReason::RestartOnDisconnectWatchdog);
+ _connecting = false;
return false;
}
- Log->print("Connection failed, retrying");
+ Log->println("Retrying");
_connectOnScanDone = true;
_openAP = false;
scan(false, true);
+ _connecting = false;
return false;
}
+ else
+ {
+ if(!_preferences->getBool(preference_wifi_converted, false))
+ {
+ _preferences->putBool(preference_wifi_converted, true);
+ }
+ _connecting = false;
+ return true;
+ }
}
- return ret;
+ return false;
}
void WifiDevice::reconfigure()
{
- bool changed = false;
- wifi_config_t wifi_cfg;
- if(esp_wifi_get_config(WIFI_IF_STA, &wifi_cfg) != ESP_OK) {
- Log->println("Failed to get Wi-Fi configuration in RAM");
- }
-
- if (esp_wifi_set_storage(WIFI_STORAGE_FLASH) != ESP_OK) {
- Log->println("Failed to set storage Wi-Fi");
- }
-
- if(sizeof(wifi_cfg.sta.ssid) > 0)
- {
- memset(wifi_cfg.sta.ssid, 0, sizeof(wifi_cfg.sta.ssid));
- changed = true;
- }
- if(sizeof(wifi_cfg.sta.password) > 0)
- {
- memset(wifi_cfg.sta.password, 0, sizeof(wifi_cfg.sta.password));
- changed = true;
- }
- if(changed)
- {
- if (esp_wifi_set_config(WIFI_IF_STA, &wifi_cfg) != ESP_OK) {
- Log->println("Failed to clear NVS Wi-Fi configuration");
- }
- }
-
_preferences->putString(preference_wifi_ssid, "");
_preferences->putString(preference_wifi_pass, "");
delay(200);
@@ -340,7 +318,16 @@ void WifiDevice::reconfigure()
bool WifiDevice::isConnected()
{
- return (WiFi.status() == WL_CONNECTED);
+ if (WiFi.status() != WL_CONNECTED)
+ {
+ return false;
+ }
+ if (!_hasIP)
+ {
+ return false;
+ }
+
+ return true;
}
void WifiDevice::onConnected()
@@ -363,12 +350,17 @@ void WifiDevice::onDisconnected()
_connecting = true;
String ssid = _preferences->getString(preference_wifi_ssid, "");
String pass = _preferences->getString(preference_wifi_pass, "");
- WiFi.begin(ssid.c_str(), pass.c_str(), _connectedChannel, _connectedBSSID, true);
- WiFi.persistent(false);
+
+ if(!_ipConfiguration->dhcpEnabled())
+ {
+ WiFi.config(_ipConfiguration->ipAddress(), _ipConfiguration->dnsServer(), _ipConfiguration->defaultGateway(), _ipConfiguration->subnet());
+ }
+
+ WiFi.begin(ssid, pass);
int loop = 0;
- while(!isConnected() && loop < 50)
+ while(!isConnected() && loop < 200)
{
loop++;
delay(100);
@@ -381,7 +373,6 @@ void WifiDevice::onDisconnected()
{
if(_preferences->getBool(preference_restart_on_disconnect, false) && ((esp_timer_get_time() / 1000) > 60000)) restartEsp(RestartReason::RestartOnDisconnectWatchdog);
- WiFi.persistent(false);
WiFi.disconnect(true);
WiFi.mode(WIFI_STA);
WiFi.disconnect();
diff --git a/src/networkDevices/WifiDevice.h b/src/networkDevices/WifiDevice.h
index 55da63f..50e9d25 100644
--- a/src/networkDevices/WifiDevice.h
+++ b/src/networkDevices/WifiDevice.h
@@ -40,6 +40,7 @@ private:
bool _startAP = true;
bool _convertOldWiFi = false;
bool _connected = false;
+ bool _hasIP = false;
uint8_t _connectedChannel = 0;
uint8_t* _connectedBSSID;
int64_t _disconnectTs = 0;