Merge pull request #29 from technyon/keypad_support

Keypad support
This commit is contained in:
Jan-Ole Schümann
2022-08-13 09:03:36 +02:00
committed by GitHub
11 changed files with 363 additions and 12 deletions

View File

@@ -15,7 +15,7 @@
#define mqtt_topic_lock_auth_name "/lock/authorizationName"
#define mqtt_topic_lock_completionStatus "/lock/completionStatus"
#define mqtt_topic_lock_action_command_result "/lock/commandResult"
#define mqtt_topic_door_sensor_state "/lock/doorSensorState"
#define mqtt_topic_lock_door_sensor_state "/lock/doorSensorState"
#define mqtt_topic_lock_action "/lock/action"
#define mqtt_topic_config_button_enabled "/configuration/buttonEnabled"
@@ -26,6 +26,14 @@
#define mqtt_topic_config_single_lock "/configuration/singleLock"
#define mqtt_topic_config_sound_level "/configuration/soundLevel"
#define mqtt_topic_keypad "/keypad"
#define mqtt_topic_keypad_command_action "/keypad/command/action"
#define mqtt_topic_keypad_command_id "/keypad/command/id"
#define mqtt_topic_keypad_command_name "/keypad/command/name"
#define mqtt_topic_keypad_command_code "/keypad/command/code"
#define mqtt_topic_keypad_command_enabled "/keypad/command/enabled"
#define mqtt_topic_keypad_command_result "/keypad/command/commandResult"
#define mqtt_topic_presence "/presence/devices"
#define mqtt_topic_reset "/maintenance/reset"

View File

@@ -53,6 +53,20 @@ void NetworkLock::initialize()
_network->subscribe(_mqttPath, mqtt_topic_reset);
_network->initTopic(_mqttPath, mqtt_topic_reset, "0");
if(_preferences->getBool(preference_keypad_control_enabled))
{
_network->subscribe(_mqttPath, mqtt_topic_keypad_command_action);
_network->subscribe(_mqttPath, mqtt_topic_keypad_command_id);
_network->subscribe(_mqttPath, mqtt_topic_keypad_command_name);
_network->subscribe(_mqttPath, mqtt_topic_keypad_command_code);
_network->subscribe(_mqttPath, mqtt_topic_keypad_command_enabled);
_network->initTopic(_mqttPath, mqtt_topic_keypad_command_action, "--");
_network->initTopic(_mqttPath, mqtt_topic_keypad_command_id, "0");
_network->initTopic(_mqttPath, mqtt_topic_keypad_command_name, "--");
_network->initTopic(_mqttPath, mqtt_topic_keypad_command_code, "000000");
_network->initTopic(_mqttPath, mqtt_topic_keypad_command_enabled, "1");
}
}
void NetworkLock::update()
@@ -98,6 +112,40 @@ void NetworkLock::onMqttDataReceived(char *&topic, byte *&payload, unsigned int
publishString(mqtt_topic_lock_action, success ? "ack" : "unknown_action");
}
if(comparePrefixedPath(topic, mqtt_topic_keypad_command_action))
{
if(_keypadCommandReceivedReceivedCallback != nullptr)
{
_keypadCommandReceivedReceivedCallback(value, _keypadCommandId, _keypadCommandName, _keypadCommandCode, _keypadCommandEnabled);
_keypadCommandId = 0;
_keypadCommandName = "--";
_keypadCommandCode = "000000";
_keypadCommandEnabled = 1;
publishString(mqtt_topic_keypad_command_action, "--");
publishInt(mqtt_topic_keypad_command_id, _keypadCommandId);
publishString(mqtt_topic_keypad_command_name, _keypadCommandName.c_str());
publishString(mqtt_topic_keypad_command_code, _keypadCommandCode.c_str());
publishInt(mqtt_topic_keypad_command_enabled, _keypadCommandEnabled);
}
}
else if(comparePrefixedPath(topic, mqtt_topic_keypad_command_id))
{
_keypadCommandId = atoi(value);
}
else if(comparePrefixedPath(topic, mqtt_topic_keypad_command_name))
{
_keypadCommandName = value;
}
else if(comparePrefixedPath(topic, mqtt_topic_keypad_command_code))
{
_keypadCommandCode = value;
}
else if(comparePrefixedPath(topic, mqtt_topic_keypad_command_enabled))
{
_keypadCommandEnabled = atoi(value);
}
for(auto configTopic : _configTopics)
{
if(comparePrefixedPath(topic, configTopic))
@@ -144,7 +192,7 @@ void NetworkLock::publishKeyTurnerState(const NukiLock::KeyTurnerState& keyTurne
{
memset(&str, 0, sizeof(str));
NukiLock::doorSensorStateToString(keyTurnerState.doorSensorState, str);
publishString(mqtt_topic_door_sensor_state, str);
publishString(mqtt_topic_lock_door_sensor_state, str);
}
if(_firstTunerStatePublish || keyTurnerState.criticalBatteryState != lastKeyTurnerState.criticalBatteryState)
@@ -216,6 +264,36 @@ void NetworkLock::publishAdvancedConfig(const NukiLock::AdvancedConfig &config)
publishBool(mqtt_topic_config_auto_lock, config.autoLockEnabled == 1);
}
void NetworkLock::publishKeypad(const std::list<NukiLock::KeypadEntry>& entries, uint maxKeypadCodeCount)
{
uint index = 0;
for(const auto& entry : entries)
{
String basePath = mqtt_topic_keypad;
basePath.concat("/code_");
basePath.concat(std::to_string(index).c_str());
publishKeypadEntry(basePath, entry);
++index;
}
while(index < maxKeypadCodeCount)
{
NukiLock::KeypadEntry entry;
memset(&entry, 0, sizeof(entry));
String basePath = mqtt_topic_keypad;
basePath.concat("/code_");
basePath.concat(std::to_string(index).c_str());
publishKeypadEntry(basePath, entry);
++index;
}
}
void NetworkLock::publishKeypadCommandResult(const char* result)
{
publishString(mqtt_topic_keypad_command_result, result);
}
void NetworkLock::setLockActionReceivedCallback(bool (*lockActionReceivedCallback)(const char *))
{
_lockActionReceivedCallback = lockActionReceivedCallback;
@@ -226,6 +304,11 @@ void NetworkLock::setConfigUpdateReceivedCallback(void (*configUpdateReceivedCal
_configUpdateReceivedCallback = configUpdateReceivedCallback;
}
void NetworkLock::setKeypadCommandReceivedCallback(void (*keypadCommandReceivedReceivedCallback)(const char* command, const uint& id, const String& name, const String& code, const int& enabled))
{
_keypadCommandReceivedReceivedCallback = keypadCommandReceivedReceivedCallback;
}
void NetworkLock::buildMqttPath(const char* path, char* outPath)
{
int offset = 0;
@@ -293,8 +376,33 @@ bool NetworkLock::publishString(const char *topic, const char *value)
return _network->publishString(_mqttPath, topic, value);
}
void NetworkLock::publishKeypadEntry(const String topic, NukiLock::KeypadEntry entry)
{
char codeName[sizeof(entry.name) + 1];
memset(codeName, 0, sizeof(codeName));
memcpy(codeName, entry.name, sizeof(entry.name));
publishInt(concat(topic, "/id").c_str(), entry.codeId);
publishBool(concat(topic, "/enabled").c_str(), entry.enabled);
publishString(concat(topic, "/name").c_str(), codeName);
publishInt(concat(topic, "/createdYear").c_str(), entry.dateCreatedYear);
publishInt(concat(topic, "/createdMonth").c_str(), entry.dateCreatedMonth);
publishInt(concat(topic, "/createdDay").c_str(), entry.dateCreatedDay);
publishInt(concat(topic, "/createdHour").c_str(), entry.dateCreatedHour);
publishInt(concat(topic, "/createdMin").c_str(), entry.dateCreatedMin);
publishInt(concat(topic, "/createdSec").c_str(), entry.dateCreatedSec);
publishInt(concat(topic, "/lockCount").c_str(), entry.lockCount);
}
void NetworkLock::publishULong(const char *topic, const unsigned long value)
{
return _network->publishULong(_mqttPath, topic, value);
}
String NetworkLock::concat(String a, String b)
{
String c = a;
c.concat(b);
return c;
}

View File

@@ -6,6 +6,7 @@
#include "networkDevices/W5500Device.h"
#include <Preferences.h>
#include <vector>
#include <list>
#include "NukiConstants.h"
#include "NukiLockConstants.h"
#include "Network.h"
@@ -28,9 +29,12 @@ public:
void publishAdvancedConfig(const NukiLock::AdvancedConfig& config);
void publishHASSConfig(char* deviceType, const char* baseTopic, char* name, char* uidString, char* lockAction, char* unlockAction, char* openAction, char* lockedState, char* unlockedState);
void removeHASSConfig(char* uidString);
void publishKeypad(const std::list<NukiLock::KeypadEntry>& entries, uint maxKeypadCodeCount);
void publishKeypadCommandResult(const char* result);
void setLockActionReceivedCallback(bool (*lockActionReceivedCallback)(const char* value));
void setConfigUpdateReceivedCallback(void (*configUpdateReceivedCallback)(const char* path, const char* value));
void setKeypadCommandReceivedCallback(void (*keypadCommandReceivedReceivedCallback)(const char* command, const uint& id, const String& name, const String& code, const int& enabled));
void onMqttDataReceived(char*& topic, byte*& payload, unsigned int& length) override;
@@ -41,8 +45,11 @@ private:
void publishULong(const char* topic, const unsigned long value);
void publishBool(const char* topic, const bool value);
bool publishString(const char* topic, const char* value);
void publishKeypadEntry(const String topic, NukiLock::KeypadEntry entry);
bool comparePrefixedPath(const char* fullPath, const char* subPath);
String concat(String a, String b);
void buildMqttPath(const char* path, char* outPath);
Network* _network;
@@ -55,6 +62,12 @@ private:
unsigned long _lastMaintenanceTs = 0;
bool _haEnabled= false;
String _keypadCommandName = "";
String _keypadCommandCode = "";
uint _keypadCommandId = 0;
int _keypadCommandEnabled = 1;
bool (*_lockActionReceivedCallback)(const char* value) = nullptr;
void (*_configUpdateReceivedCallback)(const char* path, const char* value) = nullptr;
void (*_keypadCommandReceivedReceivedCallback)(const char* command, const uint& id, const String& name, const String& code, const int& enabled) = nullptr;
};

View File

@@ -113,7 +113,7 @@ void NetworkOpener::publishKeyTurnerState(const NukiOpener::OpenerState& keyTurn
{
memset(&str, 0, sizeof(str));
NukiLock::doorSensorStateToString(keyTurnerState.doorSensorState, str);
publishString(mqtt_topic_door_sensor_state, str);
publishString(mqtt_topic_lock_door_sensor_state, str);
}
if(_firstTunerStatePublish || keyTurnerState.criticalBatteryState != lastKeyTurnerState.criticalBatteryState)

View File

@@ -23,6 +23,7 @@ NukiWrapper::NukiWrapper(const std::string& deviceName, uint32_t id, BleScanner:
network->setLockActionReceivedCallback(nukiInst->onLockActionReceivedCallback);
network->setConfigUpdateReceivedCallback(nukiInst->onConfigUpdateReceivedCallback);
network->setKeypadCommandReceivedCallback(nukiInst->onKeypadCommandReceivedCallback);
}
@@ -40,11 +41,14 @@ void NukiWrapper::initialize()
_intervalLockstate = _preferences->getInt(preference_query_interval_lockstate);
_intervalBattery = _preferences->getInt(preference_query_interval_battery);
_intervalKeypad = _preferences->getInt(preference_query_interval_keypad);
_keypadEnabled = _preferences->getBool(preference_keypad_control_enabled);
_publishAuthData = _preferences->getBool(preference_publish_authdata);
_maxKeypadCodeCount = _preferences->getUInt(preference_max_keypad_code_count);
if(_intervalLockstate == 0)
{
_intervalLockstate = 60 * 5;
_intervalLockstate = 60 * 30;
_preferences->putInt(preference_query_interval_lockstate, _intervalLockstate);
}
if(_intervalBattery == 0)
@@ -52,6 +56,11 @@ void NukiWrapper::initialize()
_intervalBattery = 60 * 30;
_preferences->putInt(preference_query_interval_battery, _intervalBattery);
}
if(_intervalKeypad == 0)
{
_intervalKeypad = 60 * 30;
_preferences->putInt(preference_query_interval_keypad, _intervalKeypad);
}
_nukiLock.setEventHandler(this);
@@ -105,6 +114,11 @@ void NukiWrapper::update()
_nextConfigUpdateTs = ts + _intervalConfig * 1000;
updateConfig();
}
if(_hasKeypad && _keypadEnabled && (_nextKeypadUpdateTs == 0 || ts > _nextKeypadUpdateTs))
{
_nextKeypadUpdateTs = ts + _intervalKeypad * 1000;
updateKeypad();
}
if(_nextLockAction != (NukiLock::LockAction)0xff)
{
@@ -189,6 +203,8 @@ void NukiWrapper::updateConfig()
{
readConfig();
readAdvancedConfig();
_configRead = true;
_hasKeypad = _nukiConfig.hasKeypad > 0;
_network->publishConfig(_nukiConfig);
_network->publishAdvancedConfig(_nukiAdvancedConfig);
}
@@ -231,6 +247,34 @@ void NukiWrapper::updateAuthData()
}
}
void NukiWrapper::updateKeypad()
{
Nuki::CmdResult result = _nukiLock.retrieveKeypadEntries(0, 0xffff);
if(result == 1)
{
std::list<NukiLock::KeypadEntry> entries;
_nukiLock.getKeypadEntries(&entries);
entries.sort([](const NukiLock::KeypadEntry& a, const NukiLock::KeypadEntry& b) { return a.codeId < b.codeId; });
uint keypadCount = entries.size();
if(keypadCount > _maxKeypadCodeCount)
{
_maxKeypadCodeCount = keypadCount;
_preferences->putUInt(preference_max_keypad_code_count, _maxKeypadCodeCount);
}
_network->publishKeypad(entries, _maxKeypadCodeCount);
_keypadCodeIds.clear();
_keypadCodeIds.reserve(entries.size());
for(const auto& entry : entries)
{
_keypadCodeIds.push_back(entry.codeId);
}
}
}
NukiLock::LockAction NukiWrapper::lockActionToEnum(const char *str)
{
if(strcmp(str, "unlock") == 0) return NukiLock::LockAction::Unlock;
@@ -258,6 +302,12 @@ void NukiWrapper::onConfigUpdateReceivedCallback(const char *topic, const char *
}
void NukiWrapper::onKeypadCommandReceivedCallback(const char *command, const uint &id, const String &name, const String &code, const int& enabled)
{
nukiInst->onKeypadCommandReceived(command, id, name, code, enabled);
}
void NukiWrapper::onConfigUpdateReceived(const char *topic, const char *value)
{
if(strcmp(topic, mqtt_topic_config_button_enabled) == 0)
@@ -311,6 +361,117 @@ void NukiWrapper::onConfigUpdateReceived(const char *topic, const char *value)
}
}
void NukiWrapper::onKeypadCommandReceived(const char *command, const uint &id, const String &name, const String &code, const int& enabled)
{
if(!_hasKeypad)
{
if(_configRead)
{
_network->publishKeypadCommandResult("KeypadNotAvailable");
}
return;
}
if(!_keypadEnabled)
{
return;
}
bool idExists = std::find(_keypadCodeIds.begin(), _keypadCodeIds.end(), id) != _keypadCodeIds.end();
int codeInt = code.toInt();
bool codeValid = codeInt > 100000 && codeInt < 1000000 && (code.indexOf('0') == -1);
NukiLock::CmdResult result = (NukiLock::CmdResult)-1;
if(strcmp(command, "add") == 0)
{
if(name == "" || name == "--")
{
_network->publishKeypadCommandResult("MissingParameterName");
return;
}
if(codeInt == 0)
{
_network->publishKeypadCommandResult("MissingParameterCode");
return;
}
if(!codeValid)
{
_network->publishKeypadCommandResult("CodeInvalid");
return;
}
NukiLock::NewKeypadEntry entry;
memset(&entry, 0, sizeof(entry));
size_t nameLen = name.length();
memcpy(&entry.name, name.c_str(), nameLen > 20 ? 20 : nameLen);
entry.code = codeInt;
result = _nukiLock.addKeypadEntry(entry);
Serial.print("Add keypad code: "); Serial.println((int)result);
updateKeypad();
}
else if(strcmp(command, "delete") == 0)
{
if(!idExists)
{
_network->publishKeypadCommandResult("UnknownId");
return;
}
result = _nukiLock.deleteKeypadEntry(id);
Serial.print("Delete keypad code: "); Serial.println((int)result);
updateKeypad();
}
else if(strcmp(command, "update") == 0)
{
if(name == "" || name == "--")
{
_network->publishKeypadCommandResult("MissingParameterName");
return;
}
if(codeInt == 0)
{
_network->publishKeypadCommandResult("MissingParameterCode");
return;
}
if(!codeValid)
{
_network->publishKeypadCommandResult("CodeInvalid");
return;
}
if(!idExists)
{
_network->publishKeypadCommandResult("UnknownId");
return;
}
NukiLock::UpdatedKeypadEntry entry;
memset(&entry, 0, sizeof(entry));
entry.codeId = id;
size_t nameLen = name.length();
memcpy(&entry.name, name.c_str(), nameLen > 20 ? 20 : nameLen);
entry.code = codeInt;
entry.enabled = enabled == 0 ? 0 : 1;
result = _nukiLock.updateKeypadEntry(entry);
Serial.print("Update keypad code: "); Serial.println((int)result);
updateKeypad();
}
else if(command == "--")
{
return;
}
else
{
_network->publishKeypadCommandResult("UnknownCommand");
return;
}
if((int)result != -1)
{
char resultStr[15];
memset(&resultStr, 0, sizeof(resultStr));
NukiLock::cmdResultToString(result, resultStr);
_network->publishKeypadCommandResult(resultStr);
}
}
const NukiLock::KeyTurnerState &NukiWrapper::keyTurnerState()
{
return _keyTurnerState;
@@ -321,6 +482,11 @@ const bool NukiWrapper::isPaired()
return _paired;
}
const bool NukiWrapper::hasKeypad()
{
return _hasKeypad;
}
void NukiWrapper::notify(Nuki::EventType eventType)
{
if(eventType == Nuki::EventType::KeyTurnerStatusUpdated)

View File

@@ -26,18 +26,22 @@ public:
const NukiLock::KeyTurnerState& keyTurnerState();
const bool isPaired();
const bool hasKeypad();
void notify(Nuki::EventType eventType) override;
private:
static bool onLockActionReceivedCallback(const char* value);
static void onConfigUpdateReceivedCallback(const char* topic, const char* value);
static void onKeypadCommandReceivedCallback(const char* command, const uint& id, const String& name, const String& code, const int& enabled);
void onConfigUpdateReceived(const char* topic, const char* value);
void onKeypadCommandReceived(const char* command, const uint& id, const String& name, const String& code, const int& enabled);
void updateKeyTurnerState();
void updateBatteryState();
void updateConfig();
void updateAuthData();
void updateKeypad();
void readConfig();
void readAdvancedConfig();
@@ -54,8 +58,10 @@ private:
int _intervalLockstate = 0; // seconds
int _intervalBattery = 0; // seconds
int _intervalConfig = 60 * 60; // seconds
int _intervalKeypad = 0; // seconds
bool _publishAuthData = false;
bool _clearAuthData = false;
std::vector<uint16_t> _keypadCodeIds;
NukiLock::KeyTurnerState _lastKeyTurnerState;
NukiLock::KeyTurnerState _keyTurnerState;
@@ -72,9 +78,13 @@ private:
bool _paired = false;
bool _statusUpdated = false;
bool _hasKeypad = false;
bool _keypadEnabled = false;
bool _configRead = false;
uint _maxKeypadCodeCount = 0;
unsigned long _nextLockStateUpdateTs = 0;
unsigned long _nextBatteryReportTs = 0;
unsigned long _nextConfigUpdateTs = 0;
unsigned long _nextPairTs = 0;
unsigned long _nextKeypadUpdateTs = 0;
NukiLock::LockAction _nextLockAction = (NukiLock::LockAction)0xff;
};

View File

@@ -10,6 +10,7 @@
#define preference_mqtt_lock_path "mqttpath"
#define preference_opener_enabled "openerena"
#define preference_mqtt_opener_path "mqttoppath"
#define preference_max_keypad_code_count "maxkpad"
#define preference_mqtt_ca "mqttca"
#define preference_mqtt_crt "mqttcrt"
#define preference_mqtt_key "mqttkey"
@@ -20,6 +21,8 @@
#define preference_restart_timer "resttmr"
#define preference_query_interval_lockstate "lockStInterval"
#define preference_query_interval_battery "batInterval"
#define preference_query_interval_keypad "kpInterval"
#define preference_keypad_control_enabled "kpEnabled"
#define preference_cred_user "crdusr"
#define preference_cred_password "crdpass"
#define preference_publish_authdata "pubauth"

View File

@@ -37,7 +37,7 @@ Just enable pairing mode on the NUKI lock (press button for a few seconds) and p
## Support
If you haven't ordered your NUKI product yet, you can support me by using my referrer code when placing your order:<br>
REFT6MTTJMBJ6<br>
REFETQHSFVW33<br>
This will also give you a 30€ discount for your order.
## MQTT Interface
@@ -91,7 +91,7 @@ This will also give you a 30€ discount for your order.
## Over-the-air Update (OTA)
After initially flashing the firmware via serial connection, further updates can be deployed via OTA update from a Web Browser. In the configuration portal, scroll down to "Firmware update" and click "Open". Then Click "Browse" and select the new "nuki_hub.bin" file and select "Upload file". After about a minute the new firmware should be installed.
## MQTT Encryption
## MQTT Encryption (optional; WiFi only)
The communication via MQTT can be SSL encrypted. To enable SSL encryption, supply the necessary information in the MQTT Configuration page.
The following configurations are supported:<br>
@@ -100,7 +100,7 @@ CA, CERT and KEY are empty -> No encryption<br>
CA is filled but CERT and KEY are empty -> Encrypted MQTT<br>
CA, CERT and KEY are filled -> Encrypted MQTT with client vaildation<br>
## Home Assistant Discovery
## Home Assistant Discovery (optional)
Home Assistant can be setup manually using the [MQTT Lock integration](https://www.home-assistant.io/integrations/lock.mqtt/).
@@ -115,6 +115,34 @@ The following mapping between Home Assistant services and Nuki commands is setup
NOTE: MQTT Discovery uses retained MQTT messages to store devices configurations. In order to avoid orphan configurations on your broker please disable autodiscovery first if you no longer want to use this SW. Retained messages are automatically cleared when unpairing and when changing/disabling autodiscovery topic in MQTT Configuration page.
## Keypad control (optional)
If a keypad is connected to the lock, keypad codes can be added, updated and removed.
This has to enabled first in the configuration portal. Check "Enabled keypad control via MQTT" and save the configuration.
After enabling keypad control, information about codes is published under "keypad/code_x", x starting from 0 up the number of configured codes.
<br>
For security reasons, the code itself is not published. To modify keypad codes, a command
structure is setup under keypad/command:
- keypad/command/id: The id of an existing code, found under keypad_code_x
- keypad/command/name: Display name of the code
- keypad/command/code: The actual 6-digit keypad code
- keypad/command/enabled: Set to 1 to enable the code, 0 to disable
- keypad/command/action: The action to execute. Possible values are add, delete and update
To modify keypad codes, the first four parameter nodes have to be set depending on the command:
- To add a code, set name, code, enabled.
- To delete a code, set id
- To update a code, set id, name, code, enabled
After setting the necessary parameters, write the action to be executed to the command node.
For example, to add a code:
- write "John Doe" to name
- write 123456 to code
- write 1 to enabled
- write "add" to action
## GPIO lock control (optional)
The lock can be controlled via GPIO. For security reasons, this has to be enabled in

View File

@@ -1,3 +1,3 @@
#pragma once
#define nuki_hub_version "5.7"
#define nuki_hub_version "5.8"

View File

@@ -286,6 +286,16 @@ bool WebCfgServer::processArgs(String& message)
_preferences->putInt(preference_query_interval_battery, value.toInt());
configChanged = true;
}
else if(key == "KPINT")
{
_preferences->putInt(preference_query_interval_keypad, value.toInt());
configChanged = true;
}
else if(key == "KPENA")
{
_preferences->putBool(preference_keypad_control_enabled, (value == "1"));
configChanged = true;
}
else if(key == "PRDTMO")
{
_preferences->putInt(preference_presence_detection_timeout, value.toInt());
@@ -557,12 +567,12 @@ void WebCfgServer::buildMqttConfigHtml(String &response)
printTextarea(response, "MQTTCA", "MQTT SSL CA Certificate (*, optional)", _preferences->getString(preference_mqtt_ca).c_str(), TLS_CA_MAX_SIZE);
printTextarea(response, "MQTTCRT", "MQTT SSL Client Certificate (*, optional)", _preferences->getString(preference_mqtt_crt).c_str(), TLS_CERT_MAX_SIZE);
printTextarea(response, "MQTTKEY", "MQTT SSL Client Key (*, optional)", _preferences->getString(preference_mqtt_key).c_str(), TLS_KEY_MAX_SIZE);
printInputField(response, "HASSDISCOVERY", "Home Assistant discovery topic (empty to disable)", _preferences->getString(preference_mqtt_hass_discovery).c_str(), 30);
printInputField(response, "HASSDISCOVERY", "Home Assistant discovery topic (empty to disable; usually homeassistant)", _preferences->getString(preference_mqtt_hass_discovery).c_str(), 30);
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));
printInputField(response, "RSTTMR", "Restart timer (minutes; -1 to disable)", _preferences->getInt(preference_restart_timer), 10);
response.concat("</table>");
response.concat("* If no encryption is configured for the MQTT broker, leave empty.<br>");
response.concat("* If no encryption is configured for the MQTT broker, leave empty. Only supported for WiFi connections.<br>");
response.concat("<br><INPUT TYPE=SUBMIT NAME=\"submit\" VALUE=\"Save\">");
response.concat("</FORM>");
@@ -589,6 +599,11 @@ void WebCfgServer::buildNukiConfigHtml(String &response)
}
printInputField(response, "LSTINT", "Query interval lock state (seconds)", _preferences->getInt(preference_query_interval_lockstate), 10);
printInputField(response, "BATINT", "Query interval battery (seconds)", _preferences->getInt(preference_query_interval_battery), 10);
if(_nuki->hasKeypad())
{
printInputField(response, "KPINT", "Query interval keypad (seconds)", _preferences->getInt(preference_query_interval_keypad), 10);
printCheckBox(response, "KPENA", "Enabled keypad control via MQTT", _preferences->getBool(preference_keypad_control_enabled));
}
printCheckBox(response, "PUBAUTH", "Publish auth data (May reduce battery life)", _preferences->getBool(preference_publish_authdata));
printCheckBox(response, "GPLCK", "Enable control via GPIO", _preferences->getBool(preference_gpio_locking_enabled));
printInputField(response, "PRDTMO", "Presence detection timeout (seconds; -1 to disable)", _preferences->getInt(preference_presence_detection_timeout), 10);