Official MQTT - Nuki Hub coexistence, keypad/timecontrol sensor per code/entry, option not to publish config, authorization log improvements, various fixes (#389)

* Coexistence with official MQTT over Wifi and Thread

* Coexistence with official MQTT over Wifi and Thread

* Arduino Core 2.0.17 cmake and README

* Coexistence with official MQTT over Wifi and Thread

* Keep updating status until state is known

* Coexistence with official MQTT over Wifi and Thread
This commit is contained in:
iranl
2024-06-08 09:03:35 +02:00
committed by GitHub
parent d2b3509d46
commit 90a8d04b45
19 changed files with 3647 additions and 1876 deletions

View File

@@ -430,6 +430,28 @@ bool WebCfgServer::processArgs(String& message)
_preferences->putBool(preference_check_updates, (value == "1"));
configChanged = true;
}
else if(key == "OFFHYBRID")
{
_preferences->putBool(preference_official_hybrid, (value == "1"));
if((value == "1")) _preferences->putBool(preference_register_as_app, true);
configChanged = true;
}
else if(key == "HYBRIDACT")
{
_preferences->putBool(preference_official_hybrid_actions, (value == "1"));
if(value == "1") _preferences->putBool(preference_register_as_app, true);
configChanged = true;
}
else if(key == "HYBRIDTIMER")
{
_preferences->putInt(preference_query_interval_hybrid_lockstate, value.toInt());
configChanged = true;
}
else if(key == "HYBRIDRETRY")
{
_preferences->putBool(preference_official_hybrid_retry, (value == "1"));
configChanged = true;
}
else if(key == "DISNONJSON")
{
_preferences->putBool(preference_disable_non_json, (value == "1"));
@@ -565,6 +587,11 @@ bool WebCfgServer::processArgs(String& message)
{
aclLvlChanged = true;
}
else if(key == "CONFPUB")
{
_preferences->putBool(preference_conf_info_enabled, (value == "1"));
configChanged = true;
}
else if(key == "KPPUB")
{
_preferences->putBool(preference_keypad_info_enabled, (value == "1"));
@@ -585,6 +612,16 @@ bool WebCfgServer::processArgs(String& message)
_preferences->putBool(preference_timecontrol_info_enabled, (value == "1"));
configChanged = true;
}
else if(key == "KPPER")
{
_preferences->putBool(preference_keypad_topic_per_entry, (value == "1"));
configChanged = true;
}
else if(key == "TCPER")
{
_preferences->putBool(preference_timecontrol_topic_per_entry, (value == "1"));
configChanged = true;
}
else if(key == "TCENA")
{
_preferences->putBool(preference_timecontrol_control_enabled, (value == "1"));
@@ -956,6 +993,11 @@ bool WebCfgServer::processArgs(String& message)
_preferences->putBool(preference_register_as_app, (value == "1"));
configChanged = true;
}
else if(key == "REGAPPOPN")
{
_preferences->putBool(preference_register_opener_as_app, (value == "1"));
configChanged = true;
}
else if(key == "LOCKENA")
{
_preferences->putBool(preference_lock_enabled, (value == "1"));
@@ -1177,9 +1219,9 @@ void WebCfgServer::buildCredHtml(String &response)
response.concat("<form class=\"adapt\" method=\"post\" action=\"savecfg\">");
response.concat("<h3>Credentials</h3>");
response.concat("<table>");
printInputField(response, "CREDUSER", "User (# to clear)", _preferences->getString(preference_cred_user).c_str(), 30, false, true);
printInputField(response, "CREDPASS", "Password", "*", 30, true, true);
printInputField(response, "CREDPASSRE", "Retype password", "*", 30, true);
printInputField(response, "CREDUSER", "User (# to clear)", _preferences->getString(preference_cred_user).c_str(), 30, "", false, true);
printInputField(response, "CREDPASS", "Password", "*", 30, "", true, true);
printInputField(response, "CREDPASSRE", "Retype password", "*", 30, "", true);
response.concat("</table>");
response.concat("<br><input type=\"submit\" name=\"submit\" value=\"Save\">");
response.concat("</form>");
@@ -1189,7 +1231,7 @@ void WebCfgServer::buildCredHtml(String &response)
response.concat("<br><br><form class=\"adapt\" method=\"post\" action=\"savecfg\">");
response.concat("<h3>Nuki Lock PIN</h3>");
response.concat("<table>");
printInputField(response, "NUKIPIN", "PIN Code (# to clear)", "*", 20, true);
printInputField(response, "NUKIPIN", "PIN Code (# to clear)", "*", 20, "", true);
response.concat("</table>");
response.concat("<br><input type=\"submit\" name=\"submit\" value=\"Save\">");
response.concat("</form>");
@@ -1200,7 +1242,7 @@ void WebCfgServer::buildCredHtml(String &response)
response.concat("<br><br><form class=\"adapt\" method=\"post\" action=\"savecfg\">");
response.concat("<h3>Nuki Opener PIN</h3>");
response.concat("<table>");
printInputField(response, "NUKIOPPIN", "PIN Code (# to clear)", "*", 20, true);
printInputField(response, "NUKIOPPIN", "PIN Code (# to clear)", "*", 20, "", true);
response.concat("</table>");
response.concat("<br><input type=\"submit\" name=\"submit\" value=\"Save\">");
response.concat("</form>");
@@ -1215,7 +1257,7 @@ void WebCfgServer::buildCredHtml(String &response)
String message = "Type ";
message.concat(_confirmCode);
message.concat(" to confirm unpair");
printInputField(response, "CONFIRMTOKEN", message.c_str(), "", 10);
printInputField(response, "CONFIRMTOKEN", message.c_str(), "", 10, "");
response.concat("</table>");
response.concat("<br><button type=\"submit\">OK</button></form>");
}
@@ -1228,7 +1270,7 @@ void WebCfgServer::buildCredHtml(String &response)
String message = "Type ";
message.concat(_confirmCode);
message.concat(" to confirm unpair");
printInputField(response, "CONFIRMTOKEN", message.c_str(), "", 10);
printInputField(response, "CONFIRMTOKEN", message.c_str(), "", 10, "");
response.concat("</table>");
response.concat("<br><button type=\"submit\">OK</button></form>");
}
@@ -1240,7 +1282,7 @@ void WebCfgServer::buildCredHtml(String &response)
String message = "Type ";
message.concat(_confirmCode);
message.concat(" to confirm factory reset");
printInputField(response, "CONFIRMTOKEN", message.c_str(), "", 10);
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>");
@@ -1304,17 +1346,17 @@ void WebCfgServer::buildMqttConfigHtml(String &response)
response.concat("<form class=\"adapt\" method=\"post\" action=\"savecfg\">");
response.concat("<h3>Basic MQTT and Network Configuration</h3>");
response.concat("<table>");
printInputField(response, "HOSTNAME", "Host name", _preferences->getString(preference_hostname).c_str(), 100);
printInputField(response, "MQTTSERVER", "MQTT Broker", _preferences->getString(preference_mqtt_broker).c_str(), 100);
printInputField(response, "MQTTPORT", "MQTT Broker port", _preferences->getInt(preference_mqtt_broker_port), 5);
printInputField(response, "MQTTUSER", "MQTT User (# to clear)", _preferences->getString(preference_mqtt_user).c_str(), 30, false, true);
printInputField(response, "MQTTPASS", "MQTT Password", "*", 30, true, true);
printInputField(response, "HOSTNAME", "Host name", _preferences->getString(preference_hostname).c_str(), 100, "");
printInputField(response, "MQTTSERVER", "MQTT Broker", _preferences->getString(preference_mqtt_broker).c_str(), 100, "");
printInputField(response, "MQTTPORT", "MQTT Broker port", _preferences->getInt(preference_mqtt_broker_port), 5, "");
printInputField(response, "MQTTUSER", "MQTT User (# to clear)", _preferences->getString(preference_mqtt_user).c_str(), 30, "", false, true);
printInputField(response, "MQTTPASS", "MQTT Password", "*", 30, "", true, true);
response.concat("</table><br>");
response.concat("<h3>Advanced MQTT and Network Configuration</h3>");
response.concat("<table>");
printInputField(response, "HASSDISCOVERY", "Home Assistant discovery topic (empty to disable; usually homeassistant)", _preferences->getString(preference_mqtt_hass_discovery).c_str(), 30);
printInputField(response, "HASSCUURL", "Home Assistant device configuration URL (empty to use http://LOCALIP; fill when using a reverse proxy for example)", _preferences->getString(preference_mqtt_hass_cu_url).c_str(), 261);
printInputField(response, "HASSDISCOVERY", "Home Assistant discovery topic (empty to disable; usually homeassistant)", _preferences->getString(preference_mqtt_hass_discovery).c_str(), 30, "");
printInputField(response, "HASSCUURL", "Home Assistant device configuration URL (empty to use http://LOCALIP; fill when using a reverse proxy for example)", _preferences->getString(preference_mqtt_hass_cu_url).c_str(), 261, "");
if(_nukiOpener != nullptr) printCheckBox(response, "OPENERCONT", "Set Nuki Opener Lock/Unlock action in Home Assistant to Continuous mode", _preferences->getBool(preference_opener_continuous_mode), "");
printTextarea(response, "MQTTCA", "MQTT SSL CA Certificate (*, optional)", _preferences->getString(preference_mqtt_ca).c_str(), TLS_CA_MAX_SIZE, _network->encryptionSupported(), true);
printTextarea(response, "MQTTCRT", "MQTT SSL Client Certificate (*, optional)", _preferences->getString(preference_mqtt_crt).c_str(), TLS_CERT_MAX_SIZE, _network->encryptionSupported(), true);
@@ -1322,22 +1364,26 @@ void WebCfgServer::buildMqttConfigHtml(String &response)
printDropDown(response, "NWHW", "Network hardware", String(_preferences->getInt(preference_network_hardware)), getNetworkDetectionOptions());
printCheckBox(response, "NWHWWIFIFB", "Disable fallback to Wi-Fi / Wi-Fi config portal", _preferences->getBool(preference_network_wifi_fallback_disabled), "");
printCheckBox(response, "BESTRSSI", "Connect to AP with the best signal in an environment with multiple APs with the same SSID", _preferences->getBool(preference_find_best_rssi), "");
printInputField(response, "RSSI", "RSSI Publish interval (seconds; -1 to disable)", _preferences->getInt(preference_rssi_publish_interval), 6);
printInputField(response, "NETTIMEOUT", "Network Timeout until restart (seconds; -1 to disable)", _preferences->getInt(preference_network_timeout), 5);
printInputField(response, "RSSI", "RSSI Publish interval (seconds; -1 to disable)", _preferences->getInt(preference_rssi_publish_interval), 6, "");
printInputField(response, "NETTIMEOUT", "Network Timeout until restart (seconds; -1 to disable)", _preferences->getInt(preference_network_timeout), 5, "");
printCheckBox(response, "RSTDISC", "Restart on disconnect", _preferences->getBool(preference_restart_on_disconnect), "");
printCheckBox(response, "MQTTLOG", "Enable MQTT logging", _preferences->getBool(preference_mqtt_log_enabled), "");
printCheckBox(response, "CHECKUPDATE", "Check for Firmware Updates every 24h", _preferences->getBool(preference_check_updates), "");
printCheckBox(response, "DISNONJSON", "Disable some extraneous non-JSON topics", _preferences->getBool(preference_disable_non_json), "");
printCheckBox(response, "OFFHYBRID", "Enable hybrid official MQTT and Nuki Hub setup", _preferences->getBool(preference_official_hybrid), "");
printCheckBox(response, "HYBRIDACT", "Enable sending actions through official MQTT", _preferences->getBool(preference_official_hybrid_actions), "");
printInputField(response, "HYBRIDTIMER", "Time between status updates when official MQTT is offline (seconds)", _preferences->getInt(preference_query_interval_hybrid_lockstate), 5, "");
printCheckBox(response, "HYBRIDRETRY", "Retry command sent using official MQTT over BLE if failed", _preferences->getBool(preference_official_hybrid_retry), "");
response.concat("</table>");
response.concat("* If no encryption is configured for the MQTT broker, leave empty. Only supported for Wi-Fi connections.<br><br>");
response.concat("<h3>IP Address assignment</h3>");
response.concat("<table>");
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);
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.concat("</table>");
response.concat("<br><input type=\"submit\" name=\"submit\" value=\"Save\">");
@@ -1356,18 +1402,20 @@ void WebCfgServer::buildAdvancedConfigHtml(String &response)
response.concat(_preferences->getBool(preference_enable_bootloop_reset, false) ? "Enabled" : "Disabled");
response.concat("</td></tr>");
printCheckBox(response, "BTLPRST", "Enable Bootloop prevention (Try to reset these settings to default on bootloop)", true, "");
printInputField(response, "BUFFSIZE", "Char buffer size (min 4096, max 32768)", _preferences->getInt(preference_buffer_size, CHAR_BUFFER_SIZE), 6);
printInputField(response, "TSKNTWK", "Task size Network (min 12288, max 32768)", _preferences->getInt(preference_task_size_network, NETWORK_TASK_SIZE), 6);
printInputField(response, "TSKNUKI", "Task size Nuki (min 8192, max 32768)", _preferences->getInt(preference_task_size_nuki, NUKI_TASK_SIZE), 6);
printInputField(response, "TSKPD", "Task size Presence Detection (min 1024, max 4048)", _preferences->getInt(preference_task_size_pd, PD_TASK_SIZE), 6);
printInputField(response, "ALMAX", "Max auth log entries (min 1, max 50)", _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 3);
printInputField(response, "KPMAX", "Max keypad entries (min 1, max 100)", _preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD), 3);
printInputField(response, "TCMAX", "Max timecontrol entries (min 1, max 50)", _preferences->getInt(preference_timecontrol_max_entries, MAX_TIMECONTROL), 3);
printInputField(response, "BUFFSIZE", "Char buffer size (min 4096, max 32768)", _preferences->getInt(preference_buffer_size, CHAR_BUFFER_SIZE), 6, "");
printInputField(response, "TSKNTWK", "Task size Network (min 12288, max 32768)", _preferences->getInt(preference_task_size_network, NETWORK_TASK_SIZE), 6, "");
printInputField(response, "TSKNUKI", "Task size Nuki (min 8192, max 32768)", _preferences->getInt(preference_task_size_nuki, NUKI_TASK_SIZE), 6, "");
printInputField(response, "TSKPD", "Task size Presence Detection (min 1024, max 4048)", _preferences->getInt(preference_task_size_pd, PD_TASK_SIZE), 6, "");
printInputField(response, "ALMAX", "Max auth log entries (min 1, max 50)", _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 3, "inputmaxauthlog");
printInputField(response, "KPMAX", "Max keypad entries (min 1, max 100)", _preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD), 3, "inputmaxkeypad");
printInputField(response, "TCMAX", "Max timecontrol entries (min 1, max 50)", _preferences->getInt(preference_timecontrol_max_entries, MAX_TIMECONTROL), 3, "inputmaxtimecontrol");
response.concat("<tr><td>Advised minimum char buffer size based on current settings</td><td id=\"mincharbuffer\"></td>");
response.concat("<tr><td>Advised minimum network task size based on current settings</td><td id=\"minnetworktask\"></td>");
response.concat("</table>");
response.concat("<br><input type=\"submit\" name=\"submit\" value=\"Save\">");
response.concat("</form>");
response.concat("</body></html>");
response.concat("</body><script>window.onload=function(){ document.getElementById(\"inputmaxauthlog\").addEventListener(\"keyup\", calculate);document.getElementById(\"inputmaxkeypad\").addEventListener(\"keyup\", calculate);document.getElementById(\"inputmaxtimecontrol\").addEventListener(\"keyup\", calculate); calculate(); }; function calculate() { var authlog = document.getElementById(\"inputmaxauthlog\").value; var keypad = document.getElementById(\"inputmaxkeypad\").value; var timecontrol = document.getElementById(\"inputmaxtimecontrol\").value; var charbuf = 0; var networktask = 0; var sizeauthlog = 0; var sizekeypad = 0; var sizetimecontrol = 0; if(authlog > 0) { sizeauthlog = 280 * authlog; } if(keypad > 0) { sizekeypad = 350 * keypad; } if(timecontrol > 0) { sizetimecontrol = 120 * timecontrol; } charbuf = sizetimecontrol; networktask = 10240 + sizetimecontrol; if(sizeauthlog>sizekeypad && sizeauthlog>sizetimecontrol) { charbuf = sizeauthlog; networktask = 10240 + sizeauthlog;} else if(sizekeypad>sizeauthlog && sizekeypad>sizetimecontrol) { charbuf = sizekeypad; networktask = 10240 + sizekeypad;} if(charbuf<4096) { charbuf = 4096; } else if (charbuf>32768) { charbuf = 32768; } if(networktask<12288) { networktask = 12288; } else if (networktask>32768) { networktask = 32768; } document.getElementById(\"mincharbuffer\").innerHTML = charbuf; document.getElementById(\"minnetworktask\").innerHTML = networktask; }</script></html>");
}
void WebCfgServer::buildStatusHtml(String &response)
@@ -1400,7 +1448,7 @@ void WebCfgServer::buildStatusHtml(String &response)
if(_nuki->isPaired())
{
json["lockPin"] = pinStateToString(_preferences->getInt(preference_lock_pin_status, 4));
lockDone = true;
if(strcmp(lockStateArr, "undefined") != 0) lockDone = true;
}
else json["lockPin"] = "Not Paired";
}
@@ -1419,7 +1467,7 @@ void WebCfgServer::buildStatusHtml(String &response)
if(_nukiOpener->isPaired())
{
json["openerPin"] = pinStateToString(_preferences->getInt(preference_opener_pin_status, 4));
openerDone = true;
if(strcmp(openerStateArr, "undefined") != 0) openerDone = true;
}
else json["openerPin"] = "Not Paired";
}
@@ -1462,14 +1510,17 @@ void WebCfgServer::buildAccLvlHtml(String &response)
response.concat("<input type=\"hidden\" name=\"ACLLVLCHANGED\" value=\"1\">");
response.concat("<h3>Nuki General Access Control</h3>");
response.concat("<table><tr><th>Setting</th><th>Enabled</th></tr>");
printCheckBox(response, "CONFPUB", "Publish Nuki configuration information", _preferences->getBool(preference_conf_info_enabled, true), "");
if((_nuki != nullptr && _nuki->hasKeypad()) || (_nukiOpener != nullptr && _nukiOpener->hasKeypad()))
{
printCheckBox(response, "KPPUB", "Publish keypad entries information", _preferences->getBool(preference_keypad_info_enabled), "");
printCheckBox(response, "KPPER", "Publish a topic per keypad entry and create HA sensor", _preferences->getBool(preference_keypad_topic_per_entry), "");
printCheckBox(response, "KPCODE", "Also publish keypad codes (<span class=\"warning\">Disadvised for security reasons</span>)", _preferences->getBool(preference_keypad_publish_code, false), "");
printCheckBox(response, "KPENA", "Add, modify and delete keypad codes", _preferences->getBool(preference_keypad_control_enabled), "");
}
printCheckBox(response, "TCPUB", "Publish time control entries information", _preferences->getBool(preference_timecontrol_info_enabled), "");
printCheckBox(response, "TCPER", "Publish a topic per time control entry and create HA sensor", _preferences->getBool(preference_timecontrol_topic_per_entry), "");
printCheckBox(response, "TCENA", "Add, modify and delete time control entries", _preferences->getBool(preference_timecontrol_control_enabled), "");
printCheckBox(response, "PUBAUTH", "Publish authorization log (may reduce battery life)", _preferences->getBool(preference_publish_authdata), "");
response.concat("</table><br>");
@@ -1548,9 +1599,9 @@ void WebCfgServer::buildAccLvlHtml(String &response)
}
if(_nukiOpener != nullptr)
{
uint32_t basicOpenerConfigAclPrefs[16];
uint32_t basicOpenerConfigAclPrefs[14];
_preferences->getBytes(preference_conf_opener_basic_acl, &basicOpenerConfigAclPrefs, sizeof(basicOpenerConfigAclPrefs));
uint32_t advancedOpenerConfigAclPrefs[22];
uint32_t advancedOpenerConfigAclPrefs[20];
_preferences->getBytes(preference_conf_opener_advanced_acl, &advancedOpenerConfigAclPrefs, sizeof(advancedOpenerConfigAclPrefs));
response.concat("<h3>Nuki Opener Access Control</h3>");
@@ -1630,32 +1681,33 @@ void WebCfgServer::buildNukiConfigHtml(String &response)
if(_preferences->getBool(preference_lock_enabled))
{
printInputField(response, "MQTTPATH", "MQTT Nuki Smartlock Path", _preferences->getString(preference_mqtt_lock_path).c_str(), 180);
printInputField(response, "MQTTPATH", "MQTT Nuki Smartlock Path", _preferences->getString(preference_mqtt_lock_path).c_str(), 180, "");
}
printCheckBox(response, "OPENA", "Nuki Opener enabled", _preferences->getBool(preference_opener_enabled), "");
if(_preferences->getBool(preference_opener_enabled))
{
printInputField(response, "MQTTOPPATH", "MQTT Nuki Opener Path", _preferences->getString(preference_mqtt_opener_path).c_str(), 180);
printInputField(response, "MQTTOPPATH", "MQTT Nuki Opener Path", _preferences->getString(preference_mqtt_opener_path).c_str(), 180, "");
}
response.concat("</table><br>");
response.concat("<h3>Advanced Nuki Configuration</h3>");
response.concat("<table>");
printInputField(response, "LSTINT", "Query interval lock state (seconds)", _preferences->getInt(preference_query_interval_lockstate), 10);
printInputField(response, "CFGINT", "Query interval configuration (seconds)", _preferences->getInt(preference_query_interval_configuration), 10);
printInputField(response, "BATINT", "Query interval battery (seconds)", _preferences->getInt(preference_query_interval_battery), 10);
printInputField(response, "LSTINT", "Query interval lock state (seconds)", _preferences->getInt(preference_query_interval_lockstate), 10, "");
printInputField(response, "CFGINT", "Query interval configuration (seconds)", _preferences->getInt(preference_query_interval_configuration), 10, "");
printInputField(response, "BATINT", "Query interval battery (seconds)", _preferences->getInt(preference_query_interval_battery), 10, "");
if((_nuki != nullptr && _nuki->hasKeypad()) || (_nukiOpener != nullptr && _nukiOpener->hasKeypad()))
{
printInputField(response, "KPINT", "Query interval keypad (seconds)", _preferences->getInt(preference_query_interval_keypad), 10);
printInputField(response, "KPINT", "Query interval keypad (seconds)", _preferences->getInt(preference_query_interval_keypad), 10, "");
}
printInputField(response, "NRTRY", "Number of retries if command failed", _preferences->getInt(preference_command_nr_of_retries), 10);
printInputField(response, "TRYDLY", "Delay between retries (milliseconds)", _preferences->getInt(preference_command_retry_delay), 10);
printCheckBox(response, "REGAPP", "Nuki Bridge is running alongside Nuki Hub (needs re-pairing if changed)", _preferences->getBool(preference_register_as_app), "");
printInputField(response, "PRDTMO", "Presence detection timeout (seconds; -1 to disable)", _preferences->getInt(preference_presence_detection_timeout), 10);
printInputField(response, "RSBC", "Restart if bluetooth beacons not received (seconds; -1 to disable)", _preferences->getInt(preference_restart_ble_beacon_lost), 10);
printInputField(response, "NRTRY", "Number of retries if command failed", _preferences->getInt(preference_command_nr_of_retries), 10, "");
printInputField(response, "TRYDLY", "Delay between retries (milliseconds)", _preferences->getInt(preference_command_retry_delay), 10, "");
if(_nuki != nullptr) printCheckBox(response, "REGAPP", "Lock: Nuki Bridge is running alongside Nuki Hub (needs re-pairing if changed)", _preferences->getBool(preference_register_as_app), "");
if(_nukiOpener != nullptr) printCheckBox(response, "REGAPPOPN", "Opener: Nuki Bridge is running alongside Nuki Hub (needs re-pairing if changed)", _preferences->getBool(preference_register_opener_as_app), "");
printInputField(response, "PRDTMO", "Presence detection timeout (seconds; -1 to disable)", _preferences->getInt(preference_presence_detection_timeout), 10, "");
printInputField(response, "RSBC", "Restart if bluetooth beacons not received (seconds; -1 to disable)", _preferences->getInt(preference_restart_ble_beacon_lost), 10, "");
response.concat("</table>");
response.concat("<br><input type=\"submit\" name=\"submit\" value=\"Save\">");
response.concat("</form>");
@@ -1845,9 +1897,9 @@ void WebCfgServer::buildInfoHtml(String &response)
if(_nukiOpener != nullptr)
{
uint32_t basicOpenerConfigAclPrefs[16];
uint32_t basicOpenerConfigAclPrefs[14];
_preferences->getBytes(preference_conf_opener_basic_acl, &basicOpenerConfigAclPrefs, sizeof(basicOpenerConfigAclPrefs));
uint32_t advancedOpenerConfigAclPrefs[22];
uint32_t advancedOpenerConfigAclPrefs[20];
_preferences->getBytes(preference_conf_opener_advanced_acl, &advancedOpenerConfigAclPrefs, sizeof(advancedOpenerConfigAclPrefs));
response.concat("Opener firmware version: ");
response.concat(_nukiOpener->firmwareVersion().c_str());
@@ -2105,6 +2157,7 @@ void WebCfgServer::printInputField(String& response,
const char *description,
const char *value,
const size_t& maxLength,
const char *id,
const bool& isPassword,
const bool& showLengthRestriction)
{
@@ -2124,7 +2177,13 @@ void WebCfgServer::printInputField(String& response,
response.concat("</td><td>");
response.concat("<input type=");
response.concat(isPassword ? "password" : "text");
response.concat(isPassword ? "\"password\"" : "\"text\"");
if(id)
{
response.concat(" id=\"");
response.concat(id);
response.concat("\"");
}
response.concat(" value=\"");
response.concat(value);
response.concat("\" name=\"");
@@ -2139,11 +2198,12 @@ void WebCfgServer::printInputField(String& response,
const char *token,
const char *description,
const int value,
size_t maxLength)
size_t maxLength,
const char *id)
{
char valueStr[20];
itoa(value, valueStr, 10);
printInputField(response, token, description, valueStr, maxLength);
printInputField(response, token, description, valueStr, maxLength, id);
}
void WebCfgServer::printCheckBox(String &response, const char *token, const char *description, const bool value, const char *htmlClass)