Merge pull request #376 from iranl/factory-reset

Add Factory Reset option
This commit is contained in:
Jan-Ole Schümann
2024-05-29 16:28:54 +07:00
committed by GitHub
4 changed files with 98 additions and 7 deletions

View File

@@ -183,6 +183,10 @@ In a browser navigate to the IP address assigned to the ESP32.
- Type [4 DIGIT CODE] to confirm unpair: Set to the shown randomly generated code to unpair the Nuki Lock or Opener from the Nuki Hub. - Type [4 DIGIT CODE] to confirm unpair: Set to the shown randomly generated code to unpair the Nuki Lock or Opener from the Nuki Hub.
#### Factory reset Nuki Hub
- Type [4 DIGIT CODE] to confirm factory reset: Set to the shown randomly generated code to reset all Nuki Hub settings to default and unpair Nuki Lock and/or Opener. Optionally also reset WiFi settings to default by enabling the checkbox.
### GPIO Configuration ### GPIO Configuration
- Gpio [2-33]: See the "[GPIO lock control](#gpio-lock-control-optional)" section of this README. - Gpio [2-33]: See the "[GPIO lock control](#gpio-lock-control-optional)" section of this README.

View File

@@ -20,6 +20,7 @@ enum class RestartReason
OTAAborted, OTAAborted,
OTAUnknownState, OTAUnknownState,
DeviceUnpaired, DeviceUnpaired,
NukiHubReset,
NotApplicable NotApplicable
}; };
@@ -100,6 +101,8 @@ inline static String getRestartReason()
return "OTAUnknownState"; return "OTAUnknownState";
case RestartReason::DeviceUnpaired: case RestartReason::DeviceUnpaired:
return "DeviceUnpaired"; return "DeviceUnpaired";
case RestartReason::NukiHubReset:
return "NukiHubFactoryReset";
case RestartReason::NotApplicable: case RestartReason::NotApplicable:
return "NotApplicable"; return "NotApplicable";
default: default:

View File

@@ -6,6 +6,7 @@
#include "Config.h" #include "Config.h"
#include "RestartReason.h" #include "RestartReason.h"
#include <esp_task_wdt.h> #include <esp_task_wdt.h>
#include <esp_wifi.h>
WebCfgServer::WebCfgServer(NukiWrapper* nuki, NukiOpenerWrapper* nukiOpener, Network* network, Gpio* gpio, EthServer* ethServer, Preferences* preferences, bool allowRestartToPortal) WebCfgServer::WebCfgServer(NukiWrapper* nuki, NukiOpenerWrapper* nukiOpener, Network* network, Gpio* gpio, EthServer* ethServer, Preferences* preferences, bool allowRestartToPortal)
: _server(ethServer), : _server(ethServer),
@@ -140,6 +141,13 @@ void WebCfgServer::initialize()
processUnpair(true); processUnpair(true);
}); });
_server.on("/factoryreset", [&]() {
if (_hasCredentials && !_server.authenticate(_credUser, _credPassword)) {
return _server.requestAuthentication();
}
processFactoryReset();
});
_server.on("/wifimanager", [&]() { _server.on("/wifimanager", [&]() {
if (_hasCredentials && !_server.authenticate(_credUser, _credPassword)) { if (_hasCredentials && !_server.authenticate(_credUser, _credPassword)) {
return _server.requestAuthentication(); return _server.requestAuthentication();
@@ -489,7 +497,7 @@ bool WebCfgServer::processArgs(String& message)
else if(key == "TSKNUKI") else if(key == "TSKNUKI")
{ {
if(value.toInt() > 8191 && value.toInt() < 32769) if(value.toInt() > 8191 && value.toInt() < 32769)
{ {
_preferences->putInt(preference_task_size_nuki, value.toInt()); _preferences->putInt(preference_task_size_nuki, value.toInt());
configChanged = true; configChanged = true;
} }
@@ -505,7 +513,7 @@ bool WebCfgServer::processArgs(String& message)
else if(key == "ALMAX") else if(key == "ALMAX")
{ {
if(value.toInt() > 0 && value.toInt() < 51) if(value.toInt() > 0 && value.toInt() < 51)
{ {
_preferences->putInt(preference_authlog_max_entries, value.toInt()); _preferences->putInt(preference_authlog_max_entries, value.toInt());
configChanged = true; configChanged = true;
} }
@@ -513,7 +521,7 @@ bool WebCfgServer::processArgs(String& message)
else if(key == "KPMAX") else if(key == "KPMAX")
{ {
if(value.toInt() > 0 && value.toInt() < 101) if(value.toInt() > 0 && value.toInt() < 101)
{ {
_preferences->putInt(preference_keypad_max_entries, value.toInt()); _preferences->putInt(preference_keypad_max_entries, value.toInt());
configChanged = true; configChanged = true;
} }
@@ -521,7 +529,7 @@ bool WebCfgServer::processArgs(String& message)
else if(key == "TCMAX") else if(key == "TCMAX")
{ {
if(value.toInt() > 0 && value.toInt() < 51) if(value.toInt() > 0 && value.toInt() < 51)
{ {
_preferences->putInt(preference_timecontrol_max_entries, value.toInt()); _preferences->putInt(preference_timecontrol_max_entries, value.toInt());
configChanged = true; configChanged = true;
} }
@@ -529,11 +537,11 @@ bool WebCfgServer::processArgs(String& message)
else if(key == "BUFFSIZE") else if(key == "BUFFSIZE")
{ {
if(value.toInt() > 4095 && value.toInt() < 32769) if(value.toInt() > 4095 && value.toInt() < 32769)
{ {
_preferences->putInt(preference_buffer_size, value.toInt()); _preferences->putInt(preference_buffer_size, value.toInt());
configChanged = true; configChanged = true;
} }
} }
else if(key == "BTLPRST") else if(key == "BTLPRST")
{ {
_preferences->putBool(preference_enable_bootloop_reset, (value == "1")); _preferences->putBool(preference_enable_bootloop_reset, (value == "1"));
@@ -1236,6 +1244,18 @@ void WebCfgServer::buildCredHtml(String &response)
response.concat("</table>"); response.concat("</table>");
response.concat("<br><button type=\"submit\">OK</button></form>"); response.concat("<br><button type=\"submit\">OK</button></form>");
} }
response.concat("<br><br><h3>Factory reset Nuki Hub</h3>");
response.concat("<h4 style=\"color: #ff0000\">This will reset all settings to default and unpair Nuki Lock and/or Opener. Optionally will also reset WiFi settings and reopen WiFi manager portal.</h4>");
response.concat("<form method=\"post\" action=\"/factoryreset\">");
response.concat("<table>");
String message = "Type ";
message.concat(_confirmCode);
message.concat(" to confirm factory reset");
printInputField(response, "CONFIRMTOKEN", message.c_str(), "", 10);
printCheckBox(response, "WIFI", "Also reset WiFi settings", false, "");
response.concat("</table>");
response.concat("<br><button type=\"submit\">OK</button></form>");
response.concat("</body></html>"); response.concat("</body></html>");
} }
@@ -1862,7 +1882,7 @@ void WebCfgServer::buildInfoHtml(String &response)
response.concat("Network device: "); response.concat("Network device: ");
response.concat(_network->networkDeviceName()); response.concat(_network->networkDeviceName());
response.concat("\n"); response.concat("\n");
if(_network->networkDeviceName() == "Built-in Wi-Fi") if(_network->networkDeviceName() == "Built-in Wi-Fi")
{ {
response.concat("BSSID of AP: "); response.concat("BSSID of AP: ");
@@ -1941,6 +1961,69 @@ void WebCfgServer::processUnpair(bool opener)
restartEsp(RestartReason::DeviceUnpaired); restartEsp(RestartReason::DeviceUnpaired);
} }
void WebCfgServer::processFactoryReset()
{
bool resetWifi = false;
String response = "";
if(_server.args() == 0)
{
buildConfirmHtml(response, "Confirm code is invalid.", 3);
_server.send(200, "text/html", response);
return;
}
else
{
String key = _server.argName(0);
String value = _server.arg(0);
if(key != "CONFIRMTOKEN" || value != _confirmCode)
{
buildConfirmHtml(response, "Confirm code is invalid.", 3);
_server.send(200, "text/html", response);
return;
}
String key2 = _server.argName(2);
String value2 = _server.arg(2);
if(key2 == "WIFI" && value2 == "1")
{
resetWifi = true;
buildConfirmHtml(response, "Factory resetting Nuki Hub, unpairing Nuki Lock and Nuki Opener and resetting WiFi.", 3);
}
else buildConfirmHtml(response, "Factory resetting Nuki Hub, unpairing Nuki Lock and Nuki Opener.", 3);
}
_server.send(200, "text/html", response);
waitAndProcess(false, 2000);
if(_nuki != nullptr)
{
_nuki->disableHASS();
_nuki->unpair();
}
if(_nukiOpener != nullptr)
{
_nukiOpener->disableHASS();
_nukiOpener->unpair();
}
_preferences->clear();
if(resetWifi)
{
wifi_config_t current_conf;
esp_wifi_get_config((wifi_interface_t)ESP_IF_WIFI_STA, &current_conf);
memset(current_conf.sta.ssid, 0, sizeof(current_conf.sta.ssid));
memset(current_conf.sta.password, 0, sizeof(current_conf.sta.password));
esp_wifi_set_config((wifi_interface_t)ESP_IF_WIFI_STA, &current_conf);
_network->reconfigureDevice();
}
waitAndProcess(false, 3000);
restartEsp(RestartReason::NukiHubReset);
}
void WebCfgServer::buildHtmlHeader(String &response) void WebCfgServer::buildHtmlHeader(String &response)
{ {
response.concat("<html><head>"); response.concat("<html><head>");

View File

@@ -51,6 +51,7 @@ private:
void sendCss(); void sendCss();
void sendFavicon(); void sendFavicon();
void processUnpair(bool opener); void processUnpair(bool opener);
void processFactoryReset();
void buildHtmlHeader(String& response); void buildHtmlHeader(String& response);
void printInputField(String& response, const char* token, const char* description, const char* value, const size_t& maxLength, const bool& isPassword = false, const bool& showLengthRestriction = false); void printInputField(String& response, const char* token, const char* description, const char* value, const size_t& maxLength, const bool& isPassword = false, const bool& showLengthRestriction = false);