Add Time Control
This commit is contained in:
@@ -52,6 +52,10 @@
|
|||||||
#define mqtt_topic_keypad_command_result "/keypad/command/commandResult"
|
#define mqtt_topic_keypad_command_result "/keypad/command/commandResult"
|
||||||
#define mqtt_topic_keypad_json "/keypad/json"
|
#define mqtt_topic_keypad_json "/keypad/json"
|
||||||
|
|
||||||
|
#define mqtt_topic_timecontrol_json "/timecontrol/json"
|
||||||
|
#define mqtt_topic_timecontrol_action "/timecontrol/action"
|
||||||
|
#define mqtt_topic_timecontrol_command_result "/timecontrol/commandResult"
|
||||||
|
|
||||||
#define mqtt_topic_info_hardware_version "/info/hardwareVersion"
|
#define mqtt_topic_info_hardware_version "/info/hardwareVersion"
|
||||||
#define mqtt_topic_info_firmware_version "/info/firmwareVersion"
|
#define mqtt_topic_info_firmware_version "/info/firmwareVersion"
|
||||||
#define mqtt_topic_info_nuki_hub_version "/info/nukiHubVersion"
|
#define mqtt_topic_info_nuki_hub_version "/info/nukiHubVersion"
|
||||||
|
|||||||
100
NetworkLock.cpp
100
NetworkLock.cpp
@@ -82,6 +82,12 @@ void NetworkLock::initialize()
|
|||||||
_network->initTopic(_mqttPath, mqtt_topic_query_keypad, "0");
|
_network->initTopic(_mqttPath, mqtt_topic_query_keypad, "0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(_preferences->getBool(preference_timecontrol_control_enabled))
|
||||||
|
{
|
||||||
|
_network->subscribe(_mqttPath, mqtt_topic_timecontrol_action);
|
||||||
|
_network->initTopic(_mqttPath, mqtt_topic_timecontrol_action, "--");
|
||||||
|
}
|
||||||
|
|
||||||
_network->addReconnectedCallback([&]()
|
_network->addReconnectedCallback([&]()
|
||||||
{
|
{
|
||||||
_reconnected = true;
|
_reconnected = true;
|
||||||
@@ -204,6 +210,18 @@ void NetworkLock::onMqttDataReceived(const char* topic, byte* payload, const uns
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(comparePrefixedPath(topic, mqtt_topic_timecontrol_action))
|
||||||
|
{
|
||||||
|
if(strcmp(value, "") == 0 || strcmp(value, "--") == 0) return;
|
||||||
|
|
||||||
|
if(_timeControlCommandReceivedReceivedCallback != NULL)
|
||||||
|
{
|
||||||
|
_timeControlCommandReceivedReceivedCallback(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
publishString(mqtt_topic_timecontrol_action, "--");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkLock::publishKeyTurnerState(const NukiLock::KeyTurnerState& keyTurnerState, const NukiLock::KeyTurnerState& lastKeyTurnerState)
|
void NetworkLock::publishKeyTurnerState(const NukiLock::KeyTurnerState& keyTurnerState, const NukiLock::KeyTurnerState& lastKeyTurnerState)
|
||||||
@@ -535,11 +553,88 @@ void NetworkLock::publishKeypad(const std::list<NukiLock::KeypadEntry>& entries,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetworkLock::publishTimeControl(const std::list<NukiLock::TimeControlEntry>& entries)
|
||||||
|
{
|
||||||
|
char str[50];
|
||||||
|
JsonDocument json;
|
||||||
|
|
||||||
|
for(const auto& entry : entries)
|
||||||
|
{
|
||||||
|
auto jsonEntry = json.add();
|
||||||
|
|
||||||
|
jsonEntry["entryId"] = entry.entryId;
|
||||||
|
jsonEntry["enabled"] = entry.enabled;
|
||||||
|
uint8_t weekdaysInt = entry.weekdays;
|
||||||
|
JsonArray weekdays = jsonEntry["weekdays"].to<JsonArray>();
|
||||||
|
|
||||||
|
while(weekdaysInt > 0) {
|
||||||
|
if(weekdaysInt >= 64)
|
||||||
|
{
|
||||||
|
weekdays.add("mon");
|
||||||
|
weekdaysInt -= 64;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(weekdaysInt >= 32)
|
||||||
|
{
|
||||||
|
weekdays.add("tue");
|
||||||
|
weekdaysInt -= 32;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(weekdaysInt >= 16)
|
||||||
|
{
|
||||||
|
weekdays.add("wed");
|
||||||
|
weekdaysInt -= 16;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(weekdaysInt >= 8)
|
||||||
|
{
|
||||||
|
weekdays.add("thu");
|
||||||
|
weekdaysInt -= 8;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(weekdaysInt >= 4)
|
||||||
|
{
|
||||||
|
weekdays.add("fri");
|
||||||
|
weekdaysInt -= 4;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(weekdaysInt >= 2)
|
||||||
|
{
|
||||||
|
weekdays.add("sat");
|
||||||
|
weekdaysInt -= 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(weekdaysInt >= 1)
|
||||||
|
{
|
||||||
|
weekdays.add("sun");
|
||||||
|
weekdaysInt -= 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char timeT[5];
|
||||||
|
sprintf(timeT, "%02d:%02d", entry.timeHour, entry.timeMin);
|
||||||
|
jsonEntry["time"] = timeT;
|
||||||
|
|
||||||
|
memset(str, 0, sizeof(str));
|
||||||
|
NukiLock::lockactionToString(entry.lockAction, str);
|
||||||
|
jsonEntry["lockAction"] = str;
|
||||||
|
}
|
||||||
|
|
||||||
|
serializeJson(json, _buffer, _bufferSize);
|
||||||
|
publishString(mqtt_topic_timecontrol_json, _buffer);
|
||||||
|
}
|
||||||
|
|
||||||
void NetworkLock::publishKeypadCommandResult(const char* result)
|
void NetworkLock::publishKeypadCommandResult(const char* result)
|
||||||
{
|
{
|
||||||
publishString(mqtt_topic_keypad_command_result, result);
|
publishString(mqtt_topic_keypad_command_result, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetworkLock::publishTimeControlCommandResult(const char* result)
|
||||||
|
{
|
||||||
|
publishString(mqtt_topic_timecontrol_command_result, result);
|
||||||
|
}
|
||||||
|
|
||||||
void NetworkLock::setLockActionReceivedCallback(LockActionResult (*lockActionReceivedCallback)(const char *))
|
void NetworkLock::setLockActionReceivedCallback(LockActionResult (*lockActionReceivedCallback)(const char *))
|
||||||
{
|
{
|
||||||
_lockActionReceivedCallback = lockActionReceivedCallback;
|
_lockActionReceivedCallback = lockActionReceivedCallback;
|
||||||
@@ -555,6 +650,11 @@ void NetworkLock::setKeypadCommandReceivedCallback(void (*keypadCommandReceivedR
|
|||||||
_keypadCommandReceivedReceivedCallback = keypadCommandReceivedReceivedCallback;
|
_keypadCommandReceivedReceivedCallback = keypadCommandReceivedReceivedCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetworkLock::setTimeControlCommandReceivedCallback(void (*timeControlCommandReceivedReceivedCallback)(const char *))
|
||||||
|
{
|
||||||
|
_timeControlCommandReceivedReceivedCallback = timeControlCommandReceivedReceivedCallback;
|
||||||
|
}
|
||||||
|
|
||||||
void NetworkLock::buildMqttPath(const char* path, char* outPath)
|
void NetworkLock::buildMqttPath(const char* path, char* outPath)
|
||||||
{
|
{
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
|
|||||||
@@ -37,12 +37,14 @@ public:
|
|||||||
void publishHASSConfig(char* deviceType, const char* baseTopic, char* name, char* uidString, const bool& hasDoorSensor, const bool& hasKeypad, const bool& publishAuthData, char* lockAction, char* unlockAction, char* openAction);
|
void publishHASSConfig(char* deviceType, const char* baseTopic, char* name, char* uidString, const bool& hasDoorSensor, const bool& hasKeypad, const bool& publishAuthData, char* lockAction, char* unlockAction, char* openAction);
|
||||||
void removeHASSConfig(char* uidString);
|
void removeHASSConfig(char* uidString);
|
||||||
void publishKeypad(const std::list<NukiLock::KeypadEntry>& entries, uint maxKeypadCodeCount);
|
void publishKeypad(const std::list<NukiLock::KeypadEntry>& entries, uint maxKeypadCodeCount);
|
||||||
|
void publishTimeControl(const std::list<NukiLock::TimeControlEntry>& entries);
|
||||||
void publishKeypadCommandResult(const char* result);
|
void publishKeypadCommandResult(const char* result);
|
||||||
|
void publishTimeControlCommandResult(const char* result);
|
||||||
|
|
||||||
void setLockActionReceivedCallback(LockActionResult (*lockActionReceivedCallback)(const char* value));
|
void setLockActionReceivedCallback(LockActionResult (*lockActionReceivedCallback)(const char* value));
|
||||||
void setConfigUpdateReceivedCallback(void (*configUpdateReceivedCallback)(const char* path, 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 setKeypadCommandReceivedCallback(void (*keypadCommandReceivedReceivedCallback)(const char* command, const uint& id, const String& name, const String& code, const int& enabled));
|
||||||
|
void setTimeControlCommandReceivedCallback(void (*timeControlCommandReceivedReceivedCallback)(const char* value));
|
||||||
void onMqttDataReceived(const char* topic, byte* payload, const unsigned int length) override;
|
void onMqttDataReceived(const char* topic, byte* payload, const unsigned int length) override;
|
||||||
|
|
||||||
bool reconnected();
|
bool reconnected();
|
||||||
@@ -90,4 +92,5 @@ private:
|
|||||||
LockActionResult (*_lockActionReceivedCallback)(const char* value) = nullptr;
|
LockActionResult (*_lockActionReceivedCallback)(const char* value) = nullptr;
|
||||||
void (*_configUpdateReceivedCallback)(const char* path, 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;
|
void (*_keypadCommandReceivedReceivedCallback)(const char* command, const uint& id, const String& name, const String& code, const int& enabled) = nullptr;
|
||||||
|
void (*_timeControlCommandReceivedReceivedCallback)(const char* value) = nullptr;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -70,6 +70,12 @@ void NetworkOpener::initialize()
|
|||||||
_network->initTopic(_mqttPath, mqtt_topic_query_keypad, "0");
|
_network->initTopic(_mqttPath, mqtt_topic_query_keypad, "0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(_preferences->getBool(preference_timecontrol_control_enabled))
|
||||||
|
{
|
||||||
|
_network->subscribe(_mqttPath, mqtt_topic_timecontrol_action);
|
||||||
|
_network->initTopic(_mqttPath, mqtt_topic_timecontrol_action, "--");
|
||||||
|
}
|
||||||
|
|
||||||
_network->addReconnectedCallback([&]()
|
_network->addReconnectedCallback([&]()
|
||||||
{
|
{
|
||||||
_reconnected = true;
|
_reconnected = true;
|
||||||
@@ -193,6 +199,18 @@ void NetworkOpener::onMqttDataReceived(const char* topic, byte* payload, const u
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(comparePrefixedPath(topic, mqtt_topic_timecontrol_action))
|
||||||
|
{
|
||||||
|
if(strcmp(value, "") == 0 || strcmp(value, "--") == 0) return;
|
||||||
|
|
||||||
|
if(_timeControlCommandReceivedReceivedCallback != NULL)
|
||||||
|
{
|
||||||
|
_timeControlCommandReceivedReceivedCallback(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
publishString(mqtt_topic_timecontrol_action, "--");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkOpener::publishKeyTurnerState(const NukiOpener::OpenerState& keyTurnerState, const NukiOpener::OpenerState& lastKeyTurnerState)
|
void NetworkOpener::publishKeyTurnerState(const NukiOpener::OpenerState& keyTurnerState, const NukiOpener::OpenerState& lastKeyTurnerState)
|
||||||
@@ -282,7 +300,7 @@ void NetworkOpener::publishRing(const bool locked)
|
|||||||
{
|
{
|
||||||
publishString(mqtt_topic_lock_ring, "ring");
|
publishString(mqtt_topic_lock_ring, "ring");
|
||||||
}
|
}
|
||||||
|
|
||||||
publishString(mqtt_topic_lock_binary_ring, "ring");
|
publishString(mqtt_topic_lock_binary_ring, "ring");
|
||||||
_resetRingStateTs = millis() + 2000;
|
_resetRingStateTs = millis() + 2000;
|
||||||
}
|
}
|
||||||
@@ -591,11 +609,88 @@ void NetworkOpener::publishKeypad(const std::list<NukiLock::KeypadEntry>& entrie
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetworkOpener::publishTimeControl(const std::list<NukiLock::TimeControlEntry>& entries)
|
||||||
|
{
|
||||||
|
char str[50];
|
||||||
|
JsonDocument json;
|
||||||
|
|
||||||
|
for(const auto& entry : entries)
|
||||||
|
{
|
||||||
|
auto jsonEntry = json.add();
|
||||||
|
|
||||||
|
jsonEntry["entryId"] = entry.entryId;
|
||||||
|
jsonEntry["enabled"] = entry.enabled;
|
||||||
|
uint8_t weekdaysInt = entry.weekdays;
|
||||||
|
JsonArray weekdays = jsonEntry["weekdays"].to<JsonArray>();
|
||||||
|
|
||||||
|
while(weekdaysInt > 0) {
|
||||||
|
if(weekdaysInt >= 64)
|
||||||
|
{
|
||||||
|
weekdays.add("mon");
|
||||||
|
weekdaysInt -= 64;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(weekdaysInt >= 32)
|
||||||
|
{
|
||||||
|
weekdays.add("tue");
|
||||||
|
weekdaysInt -= 32;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(weekdaysInt >= 16)
|
||||||
|
{
|
||||||
|
weekdays.add("wed");
|
||||||
|
weekdaysInt -= 16;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(weekdaysInt >= 8)
|
||||||
|
{
|
||||||
|
weekdays.add("thu");
|
||||||
|
weekdaysInt -= 8;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(weekdaysInt >= 4)
|
||||||
|
{
|
||||||
|
weekdays.add("fri");
|
||||||
|
weekdaysInt -= 4;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(weekdaysInt >= 2)
|
||||||
|
{
|
||||||
|
weekdays.add("sat");
|
||||||
|
weekdaysInt -= 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(weekdaysInt >= 1)
|
||||||
|
{
|
||||||
|
weekdays.add("sun");
|
||||||
|
weekdaysInt -= 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char timeT[5];
|
||||||
|
sprintf(timeT, "%02d:%02d", entry.timeHour, entry.timeMin);
|
||||||
|
jsonEntry["time"] = timeT;
|
||||||
|
|
||||||
|
memset(str, 0, sizeof(str));
|
||||||
|
NetworkOpener::lockactionToString(entry.lockAction, str);
|
||||||
|
jsonEntry["lockAction"] = str;
|
||||||
|
}
|
||||||
|
|
||||||
|
serializeJson(json, _buffer, _bufferSize);
|
||||||
|
publishString(mqtt_topic_timecontrol_json, _buffer);
|
||||||
|
}
|
||||||
|
|
||||||
void NetworkOpener::publishKeypadCommandResult(const char* result)
|
void NetworkOpener::publishKeypadCommandResult(const char* result)
|
||||||
{
|
{
|
||||||
publishString(mqtt_topic_keypad_command_result, result);
|
publishString(mqtt_topic_keypad_command_result, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetworkOpener::publishTimeControlCommandResult(const char* result)
|
||||||
|
{
|
||||||
|
publishString(mqtt_topic_timecontrol_command_result, result);
|
||||||
|
}
|
||||||
|
|
||||||
void NetworkOpener::setLockActionReceivedCallback(LockActionResult (*lockActionReceivedCallback)(const char *))
|
void NetworkOpener::setLockActionReceivedCallback(LockActionResult (*lockActionReceivedCallback)(const char *))
|
||||||
{
|
{
|
||||||
_lockActionReceivedCallback = lockActionReceivedCallback;
|
_lockActionReceivedCallback = lockActionReceivedCallback;
|
||||||
@@ -611,6 +706,11 @@ void NetworkOpener::setKeypadCommandReceivedCallback(void (*keypadCommandReceive
|
|||||||
_keypadCommandReceivedReceivedCallback = keypadCommandReceivedReceivedCallback;
|
_keypadCommandReceivedReceivedCallback = keypadCommandReceivedReceivedCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetworkOpener::setTimeControlCommandReceivedCallback(void (*timeControlCommandReceivedReceivedCallback)(const char *))
|
||||||
|
{
|
||||||
|
_timeControlCommandReceivedReceivedCallback = timeControlCommandReceivedReceivedCallback;
|
||||||
|
}
|
||||||
|
|
||||||
void NetworkOpener::publishFloat(const char *topic, const float value, const uint8_t precision)
|
void NetworkOpener::publishFloat(const char *topic, const float value, const uint8_t precision)
|
||||||
{
|
{
|
||||||
_network->publishFloat(_mqttPath, topic, value, precision);
|
_network->publishFloat(_mqttPath, topic, value, precision);
|
||||||
|
|||||||
@@ -34,12 +34,14 @@ public:
|
|||||||
void publishHASSConfig(char* deviceType, const char* baseTopic, char* name, char* uidString, char* lockAction, char* unlockAction, char* openAction);
|
void publishHASSConfig(char* deviceType, const char* baseTopic, char* name, char* uidString, char* lockAction, char* unlockAction, char* openAction);
|
||||||
void removeHASSConfig(char* uidString);
|
void removeHASSConfig(char* uidString);
|
||||||
void publishKeypad(const std::list<NukiLock::KeypadEntry>& entries, uint maxKeypadCodeCount);
|
void publishKeypad(const std::list<NukiLock::KeypadEntry>& entries, uint maxKeypadCodeCount);
|
||||||
|
void publishTimeControl(const std::list<NukiLock::TimeControlEntry>& entries);
|
||||||
void publishKeypadCommandResult(const char* result);
|
void publishKeypadCommandResult(const char* result);
|
||||||
|
void publishTimeControlCommandResult(const char* result);
|
||||||
|
|
||||||
void setLockActionReceivedCallback(LockActionResult (*lockActionReceivedCallback)(const char* value));
|
void setLockActionReceivedCallback(LockActionResult (*lockActionReceivedCallback)(const char* value));
|
||||||
void setConfigUpdateReceivedCallback(void (*configUpdateReceivedCallback)(const char* path, 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 setKeypadCommandReceivedCallback(void (*keypadCommandReceivedReceivedCallback)(const char* command, const uint& id, const String& name, const String& code, const int& enabled));
|
||||||
|
void setTimeControlCommandReceivedCallback(void (*timeControlCommandReceivedReceivedCallback)(const char* value));
|
||||||
void onMqttDataReceived(const char* topic, byte* payload, const unsigned int length) override;
|
void onMqttDataReceived(const char* topic, byte* payload, const unsigned int length) override;
|
||||||
|
|
||||||
bool reconnected();
|
bool reconnected();
|
||||||
@@ -93,4 +95,5 @@ private:
|
|||||||
LockActionResult (*_lockActionReceivedCallback)(const char* value) = nullptr;
|
LockActionResult (*_lockActionReceivedCallback)(const char* value) = nullptr;
|
||||||
void (*_configUpdateReceivedCallback)(const char* path, 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;
|
void (*_keypadCommandReceivedReceivedCallback)(const char* command, const uint& id, const String& name, const String& code, const int& enabled) = nullptr;
|
||||||
|
void (*_timeControlCommandReceivedReceivedCallback)(const char* value) = nullptr;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -412,6 +412,8 @@ void NukiOpenerWrapper::updateConfig()
|
|||||||
_hardwareVersion = std::to_string(_nukiConfig.hardwareRevision[0]) + "." + std::to_string(_nukiConfig.hardwareRevision[1]);
|
_hardwareVersion = std::to_string(_nukiConfig.hardwareRevision[0]) + "." + std::to_string(_nukiConfig.hardwareRevision[1]);
|
||||||
_network->publishConfig(_nukiConfig);
|
_network->publishConfig(_nukiConfig);
|
||||||
_retryConfigCount = 0;
|
_retryConfigCount = 0;
|
||||||
|
|
||||||
|
if(_preferences->getBool(preference_timecontrol_info_enabled)) updateTimeControl();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -505,6 +507,31 @@ void NukiOpenerWrapper::updateKeypad()
|
|||||||
postponeBleWatchdog();
|
postponeBleWatchdog();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NukiOpenerWrapper::updateTimeControl()
|
||||||
|
{
|
||||||
|
if(!_preferences->getBool(preference_timecontrol_info_enabled)) return;
|
||||||
|
|
||||||
|
Log->print(F("Querying lock time control: "));
|
||||||
|
Nuki::CmdResult result = _nukiOpener.retrieveTimeControlEntries();
|
||||||
|
printCommandResult(result);
|
||||||
|
if(result == Nuki::CmdResult::Success)
|
||||||
|
{
|
||||||
|
std::list<NukiLock::TimeControlEntry> entries;
|
||||||
|
_nukiOpener.getTimeControlEntries(&entries);
|
||||||
|
|
||||||
|
entries.sort([](const NukiLock::TimeControlEntry& a, const NukiLock::TimeControlEntry& b) { return a.entryId < b.entryId; });
|
||||||
|
|
||||||
|
_timeControlIds.clear();
|
||||||
|
_timeControlIds.reserve(entries.size());
|
||||||
|
for(const auto& entry : entries)
|
||||||
|
{
|
||||||
|
_timeControlIds.push_back(entry.entryId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
postponeBleWatchdog();
|
||||||
|
}
|
||||||
|
|
||||||
void NukiOpenerWrapper::postponeBleWatchdog()
|
void NukiOpenerWrapper::postponeBleWatchdog()
|
||||||
{
|
{
|
||||||
_disableBleWatchdogTs = millis() + 15000;
|
_disableBleWatchdogTs = millis() + 15000;
|
||||||
@@ -726,6 +753,169 @@ void NukiOpenerWrapper::onKeypadCommandReceived(const char *command, const uint
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NukiOpenerWrapper::onTimeControlCommandReceived(const char *value)
|
||||||
|
{
|
||||||
|
if(_nukiLock.getSecurityPincode() == 0)
|
||||||
|
{
|
||||||
|
_network->publishTimeControlCommandResult("noPinSet");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!_preferences->getBool(preference_timecontrol_control_enabled))
|
||||||
|
{
|
||||||
|
_network->publishTimeControlCommandResult("timeControlControlDisabled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonDocument json;
|
||||||
|
DeserializationError jsonError = deserializeJson(json, value);
|
||||||
|
|
||||||
|
if(jsonError)
|
||||||
|
{
|
||||||
|
_network->publishTimeControlCommandResult("invalidJson");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Nuki::CmdResult result = (Nuki::CmdResult)-1;
|
||||||
|
|
||||||
|
const char *action = json["action"].as<const char*>();
|
||||||
|
uint8_t entryId = json["entryId"].as<unsigned int>();
|
||||||
|
uint8_t enabled = json["enabled"].as<unsigned int>();
|
||||||
|
String weekdays = json["weekdays"].as<String>();
|
||||||
|
const char *time = json["time"].as<const char*>();
|
||||||
|
NukiOpener::LockAction timeControlLockAction = nukiOpenerInst->lockActionToEnum(json["lockAction"].as<const char*>());
|
||||||
|
|
||||||
|
if((int)timeControlLockAction == 0xff)
|
||||||
|
{
|
||||||
|
_network->publishTimeControlCommandResult("invalidLockAction");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(action)
|
||||||
|
{
|
||||||
|
bool idExists = false;
|
||||||
|
|
||||||
|
if(entryId)
|
||||||
|
{
|
||||||
|
idExists = std::find(_timeControlIds.begin(), _timeControlIds.end(), entryId) != _timeControlIds.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strcmp(action, "delete") == 0) {
|
||||||
|
if(idExists)
|
||||||
|
{
|
||||||
|
result = _nukiOpener.removeTimeControlEntry(entryId);
|
||||||
|
Log->print("Delete time control ");
|
||||||
|
Log->println((int)result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_network->publishTimeControlCommandResult("noExistingEntryIdSet");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(strcmp(action, "add") == 0 || strcmp(action, "update") == 0)
|
||||||
|
{
|
||||||
|
uint8_t timeHour;
|
||||||
|
uint8_t timeMin;
|
||||||
|
uint8_t weekdaysInt = 0;
|
||||||
|
unsigned int timeAr[2];
|
||||||
|
|
||||||
|
if(time)
|
||||||
|
{
|
||||||
|
if(strlen(time) == 5)
|
||||||
|
{
|
||||||
|
String timeStr = time;
|
||||||
|
timeAr[0] = (uint8_t)timeStr.substring(0, 2).toInt();
|
||||||
|
timeAr[1] = (uint8_t)timeStr.substring(3, 5).toInt();
|
||||||
|
|
||||||
|
if(timeAr[0] < 0 || timeAr[0] > 23 || timeAr[1] < 0 || timeAr[1] > 59)
|
||||||
|
{
|
||||||
|
_network->publishKeypadJsonCommandResult("invalidTime");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_network->publishKeypadJsonCommandResult("invalidTime");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_network->publishKeypadJsonCommandResult("invalidTime");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(weekdays.indexOf("mon") >= 0) weekdaysInt += 64;
|
||||||
|
if(weekdays.indexOf("tue") >= 0) weekdaysInt += 32;
|
||||||
|
if(weekdays.indexOf("wed") >= 0) weekdaysInt += 16;
|
||||||
|
if(weekdays.indexOf("thu") >= 0) weekdaysInt += 8;
|
||||||
|
if(weekdays.indexOf("fri") >= 0) weekdaysInt += 4;
|
||||||
|
if(weekdays.indexOf("sat") >= 0) weekdaysInt += 2;
|
||||||
|
if(weekdays.indexOf("sun") >= 0) weekdaysInt += 1;
|
||||||
|
|
||||||
|
if(strcmp(action, "add") == 0)
|
||||||
|
{
|
||||||
|
NukiLock::NewTimeControlEntry entry;
|
||||||
|
memset(&entry, 0, sizeof(entry));
|
||||||
|
entry.weekdays = weekdaysInt;
|
||||||
|
|
||||||
|
if(time)
|
||||||
|
{
|
||||||
|
entry.timeHour = timeAr[0];
|
||||||
|
entry.timeMin = timeAr[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.lockAction = timeControlLockAction;
|
||||||
|
|
||||||
|
result = _nukiOpener.addKeypadEntry(entry);
|
||||||
|
Log->print("Add time control: ");
|
||||||
|
Log->println((int)result);
|
||||||
|
}
|
||||||
|
else if (strcmp(action, "update") == 0)
|
||||||
|
{
|
||||||
|
NukiLock::TimeControlEntry entry;
|
||||||
|
memset(&entry, 0, sizeof(entry));
|
||||||
|
entry.entryId = entryId;
|
||||||
|
entry.enabled = enabled == 0 ? 0 : 1;
|
||||||
|
entry.weekdays = weekdaysInt;
|
||||||
|
|
||||||
|
if(time)
|
||||||
|
{
|
||||||
|
entry.timeHour = timeAr[0];
|
||||||
|
entry.timeMin = timeAr[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.lockAction = timeControlLockAction;
|
||||||
|
|
||||||
|
result = _nukiOpener.updateTimeControlEntry(entry);
|
||||||
|
Log->print("Update time control: ");
|
||||||
|
Log->println((int)result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_network->publishTimeControlCommandResult("invalidAction");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((int)result != -1)
|
||||||
|
{
|
||||||
|
char resultStr[15];
|
||||||
|
memset(&resultStr, 0, sizeof(resultStr));
|
||||||
|
NukiLock::cmdResultToString(result, resultStr);
|
||||||
|
_network->publishTimeControlCommandResult(resultStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
_nextConfigUpdateTs = millis() + 300;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_network->publishTimeControlCommandResult("noActionSet");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const NukiOpener::OpenerState &NukiOpenerWrapper::keyTurnerState()
|
const NukiOpener::OpenerState &NukiOpenerWrapper::keyTurnerState()
|
||||||
{
|
{
|
||||||
return _keyTurnerState;
|
return _keyTurnerState;
|
||||||
|
|||||||
@@ -49,15 +49,18 @@ private:
|
|||||||
static LockActionResult onLockActionReceivedCallback(const char* value);
|
static LockActionResult onLockActionReceivedCallback(const char* value);
|
||||||
static void onConfigUpdateReceivedCallback(const char* topic, 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);
|
static void onKeypadCommandReceivedCallback(const char* command, const uint& id, const String& name, const String& code, const int& enabled);
|
||||||
|
static void onTimeControlCommandReceivedCallback(const char* value);
|
||||||
static void gpioActionCallback(const GpioAction& action, const int& pin);
|
static void gpioActionCallback(const GpioAction& action, const int& pin);
|
||||||
void onConfigUpdateReceived(const char* topic, const char* value);
|
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 onKeypadCommandReceived(const char* command, const uint& id, const String& name, const String& code, const int& enabled);
|
||||||
|
void onTimeControlCommandReceived(const char* value);
|
||||||
|
|
||||||
void updateKeyTurnerState();
|
void updateKeyTurnerState();
|
||||||
void updateBatteryState();
|
void updateBatteryState();
|
||||||
void updateConfig();
|
void updateConfig();
|
||||||
void updateAuthData();
|
void updateAuthData();
|
||||||
void updateKeypad();
|
void updateKeypad();
|
||||||
|
void updateTimeControl();
|
||||||
void postponeBleWatchdog();
|
void postponeBleWatchdog();
|
||||||
|
|
||||||
void updateGpioOutputs();
|
void updateGpioOutputs();
|
||||||
@@ -92,6 +95,7 @@ private:
|
|||||||
int _retryLockstateCount = 0;
|
int _retryLockstateCount = 0;
|
||||||
unsigned long _nextRetryTs = 0;
|
unsigned long _nextRetryTs = 0;
|
||||||
std::vector<uint16_t> _keypadCodeIds;
|
std::vector<uint16_t> _keypadCodeIds;
|
||||||
|
std::vector<uint8_t> _timeControlIds;
|
||||||
|
|
||||||
NukiOpener::OpenerState _lastKeyTurnerState;
|
NukiOpener::OpenerState _lastKeyTurnerState;
|
||||||
NukiOpener::OpenerState _keyTurnerState;
|
NukiOpener::OpenerState _keyTurnerState;
|
||||||
|
|||||||
196
NukiWrapper.cpp
196
NukiWrapper.cpp
@@ -32,6 +32,7 @@ NukiWrapper::NukiWrapper(const std::string& deviceName, NukiDeviceId* deviceId,
|
|||||||
network->setLockActionReceivedCallback(nukiInst->onLockActionReceivedCallback);
|
network->setLockActionReceivedCallback(nukiInst->onLockActionReceivedCallback);
|
||||||
network->setConfigUpdateReceivedCallback(nukiInst->onConfigUpdateReceivedCallback);
|
network->setConfigUpdateReceivedCallback(nukiInst->onConfigUpdateReceivedCallback);
|
||||||
network->setKeypadCommandReceivedCallback(nukiInst->onKeypadCommandReceivedCallback);
|
network->setKeypadCommandReceivedCallback(nukiInst->onKeypadCommandReceivedCallback);
|
||||||
|
network->setTimeControlCommandReceivedCallback(nukiInst->onTimeControlCommandReceivedCallback);
|
||||||
|
|
||||||
_gpio->addCallback(NukiWrapper::gpioActionCallback);
|
_gpio->addCallback(NukiWrapper::gpioActionCallback);
|
||||||
}
|
}
|
||||||
@@ -378,6 +379,8 @@ void NukiWrapper::updateConfig()
|
|||||||
_hardwareVersion = std::to_string(_nukiConfig.hardwareRevision[0]) + "." + std::to_string(_nukiConfig.hardwareRevision[1]);
|
_hardwareVersion = std::to_string(_nukiConfig.hardwareRevision[0]) + "." + std::to_string(_nukiConfig.hardwareRevision[1]);
|
||||||
_network->publishConfig(_nukiConfig);
|
_network->publishConfig(_nukiConfig);
|
||||||
_retryConfigCount = 0;
|
_retryConfigCount = 0;
|
||||||
|
|
||||||
|
if(_preferences->getBool(preference_timecontrol_info_enabled)) updateTimeControl();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -471,6 +474,31 @@ void NukiWrapper::updateKeypad()
|
|||||||
postponeBleWatchdog();
|
postponeBleWatchdog();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NukiWrapper::updateTimeControl()
|
||||||
|
{
|
||||||
|
if(!_preferences->getBool(preference_timecontrol_info_enabled)) return;
|
||||||
|
|
||||||
|
Log->print(F("Querying lock time control: "));
|
||||||
|
Nuki::CmdResult result = _nukiLock.retrieveTimeControlEntries();
|
||||||
|
printCommandResult(result);
|
||||||
|
if(result == Nuki::CmdResult::Success)
|
||||||
|
{
|
||||||
|
std::list<NukiLock::TimeControlEntry> entries;
|
||||||
|
_nukiLock.getTimeControlEntries(&entries);
|
||||||
|
|
||||||
|
entries.sort([](const NukiLock::TimeControlEntry& a, const NukiLock::TimeControlEntry& b) { return a.entryId < b.entryId; });
|
||||||
|
|
||||||
|
_timeControlIds.clear();
|
||||||
|
_timeControlIds.reserve(entries.size());
|
||||||
|
for(const auto& entry : entries)
|
||||||
|
{
|
||||||
|
_timeControlIds.push_back(entry.entryId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
postponeBleWatchdog();
|
||||||
|
}
|
||||||
|
|
||||||
void NukiWrapper::postponeBleWatchdog()
|
void NukiWrapper::postponeBleWatchdog()
|
||||||
{
|
{
|
||||||
_disableBleWatchdogTs = millis() + 15000;
|
_disableBleWatchdogTs = millis() + 15000;
|
||||||
@@ -525,6 +553,11 @@ void NukiWrapper::onKeypadCommandReceivedCallback(const char *command, const uin
|
|||||||
nukiInst->onKeypadCommandReceived(command, id, name, code, enabled);
|
nukiInst->onKeypadCommandReceived(command, id, name, code, enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NukiWrapper::onTimeControlCommandReceivedCallback(const char *value)
|
||||||
|
{
|
||||||
|
nukiInst->onTimeControlCommandReceived(value);
|
||||||
|
}
|
||||||
|
|
||||||
void NukiWrapper::gpioActionCallback(const GpioAction &action, const int& pin)
|
void NukiWrapper::gpioActionCallback(const GpioAction &action, const int& pin)
|
||||||
{
|
{
|
||||||
switch(action)
|
switch(action)
|
||||||
@@ -712,6 +745,169 @@ void NukiWrapper::onKeypadCommandReceived(const char *command, const uint &id, c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NukiWrapper::onTimeControlCommandReceived(const char *value)
|
||||||
|
{
|
||||||
|
if(_nukiLock.getSecurityPincode() == 0)
|
||||||
|
{
|
||||||
|
_network->publishTimeControlCommandResult("noPinSet");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!_preferences->getBool(preference_timecontrol_control_enabled))
|
||||||
|
{
|
||||||
|
_network->publishTimeControlCommandResult("timeControlControlDisabled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonDocument json;
|
||||||
|
DeserializationError jsonError = deserializeJson(json, value);
|
||||||
|
|
||||||
|
if(jsonError)
|
||||||
|
{
|
||||||
|
_network->publishTimeControlCommandResult("invalidJson");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Nuki::CmdResult result = (Nuki::CmdResult)-1;
|
||||||
|
|
||||||
|
const char *action = json["action"].as<const char*>();
|
||||||
|
uint8_t entryId = json["entryId"].as<unsigned int>();
|
||||||
|
uint8_t enabled = json["enabled"].as<unsigned int>();
|
||||||
|
String weekdays = json["weekdays"].as<String>();
|
||||||
|
const char *time = json["time"].as<const char*>();
|
||||||
|
NukiLock::LockAction timeControlLockAction = nukiInst->lockActionToEnum(json["lockAction"].as<const char*>());
|
||||||
|
|
||||||
|
if((int)timeControlLockAction == 0xff)
|
||||||
|
{
|
||||||
|
_network->publishTimeControlCommandResult("invalidLockAction");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(action)
|
||||||
|
{
|
||||||
|
bool idExists = false;
|
||||||
|
|
||||||
|
if(entryId)
|
||||||
|
{
|
||||||
|
idExists = std::find(_timeControlIds.begin(), _timeControlIds.end(), entryId) != _timeControlIds.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strcmp(action, "delete") == 0) {
|
||||||
|
if(idExists)
|
||||||
|
{
|
||||||
|
result = _nukiLock.removeTimeControlEntry(entryId);
|
||||||
|
Log->print("Delete time control ");
|
||||||
|
Log->println((int)result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_network->publishTimeControlCommandResult("noExistingEntryIdSet");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(strcmp(action, "add") == 0 || strcmp(action, "update") == 0)
|
||||||
|
{
|
||||||
|
uint8_t timeHour;
|
||||||
|
uint8_t timeMin;
|
||||||
|
uint8_t weekdaysInt = 0;
|
||||||
|
unsigned int timeAr[2];
|
||||||
|
|
||||||
|
if(time)
|
||||||
|
{
|
||||||
|
if(strlen(time) == 5)
|
||||||
|
{
|
||||||
|
String timeStr = time;
|
||||||
|
timeAr[0] = (uint8_t)timeStr.substring(0, 2).toInt();
|
||||||
|
timeAr[1] = (uint8_t)timeStr.substring(3, 5).toInt();
|
||||||
|
|
||||||
|
if(timeAr[0] < 0 || timeAr[0] > 23 || timeAr[1] < 0 || timeAr[1] > 59)
|
||||||
|
{
|
||||||
|
_network->publishKeypadJsonCommandResult("invalidTime");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_network->publishKeypadJsonCommandResult("invalidTime");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_network->publishKeypadJsonCommandResult("invalidTime");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(weekdays.indexOf("mon") >= 0) weekdaysInt += 64;
|
||||||
|
if(weekdays.indexOf("tue") >= 0) weekdaysInt += 32;
|
||||||
|
if(weekdays.indexOf("wed") >= 0) weekdaysInt += 16;
|
||||||
|
if(weekdays.indexOf("thu") >= 0) weekdaysInt += 8;
|
||||||
|
if(weekdays.indexOf("fri") >= 0) weekdaysInt += 4;
|
||||||
|
if(weekdays.indexOf("sat") >= 0) weekdaysInt += 2;
|
||||||
|
if(weekdays.indexOf("sun") >= 0) weekdaysInt += 1;
|
||||||
|
|
||||||
|
if(strcmp(action, "add") == 0)
|
||||||
|
{
|
||||||
|
NukiLock::NewTimeControlEntry entry;
|
||||||
|
memset(&entry, 0, sizeof(entry));
|
||||||
|
entry.weekdays = weekdaysInt;
|
||||||
|
|
||||||
|
if(time)
|
||||||
|
{
|
||||||
|
entry.timeHour = timeAr[0];
|
||||||
|
entry.timeMin = timeAr[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.lockAction = timeControlLockAction;
|
||||||
|
|
||||||
|
result = _nukiLock.addKeypadEntry(entry);
|
||||||
|
Log->print("Add time control: ");
|
||||||
|
Log->println((int)result);
|
||||||
|
}
|
||||||
|
else if (strcmp(action, "update") == 0)
|
||||||
|
{
|
||||||
|
NukiLock::TimeControlEntry entry;
|
||||||
|
memset(&entry, 0, sizeof(entry));
|
||||||
|
entry.entryId = entryId;
|
||||||
|
entry.enabled = enabled == 0 ? 0 : 1;
|
||||||
|
entry.weekdays = weekdaysInt;
|
||||||
|
|
||||||
|
if(time)
|
||||||
|
{
|
||||||
|
entry.timeHour = timeAr[0];
|
||||||
|
entry.timeMin = timeAr[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.lockAction = timeControlLockAction;
|
||||||
|
|
||||||
|
result = _nukiLock.updateTimeControlEntry(entry);
|
||||||
|
Log->print("Update time control: ");
|
||||||
|
Log->println((int)result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_network->publishTimeControlCommandResult("invalidAction");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((int)result != -1)
|
||||||
|
{
|
||||||
|
char resultStr[15];
|
||||||
|
memset(&resultStr, 0, sizeof(resultStr));
|
||||||
|
NukiLock::cmdResultToString(result, resultStr);
|
||||||
|
_network->publishTimeControlCommandResult(resultStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
_nextConfigUpdateTs = millis() + 300;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_network->publishTimeControlCommandResult("noActionSet");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const NukiLock::KeyTurnerState &NukiWrapper::keyTurnerState()
|
const NukiLock::KeyTurnerState &NukiWrapper::keyTurnerState()
|
||||||
{
|
{
|
||||||
return _keyTurnerState;
|
return _keyTurnerState;
|
||||||
|
|||||||
@@ -47,16 +47,19 @@ private:
|
|||||||
static LockActionResult onLockActionReceivedCallback(const char* value);
|
static LockActionResult onLockActionReceivedCallback(const char* value);
|
||||||
static void onConfigUpdateReceivedCallback(const char* topic, 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);
|
static void onKeypadCommandReceivedCallback(const char* command, const uint& id, const String& name, const String& code, const int& enabled);
|
||||||
|
static void onTimeControlCommandReceivedCallback(const char* value);
|
||||||
static void gpioActionCallback(const GpioAction& action, const int& pin);
|
static void gpioActionCallback(const GpioAction& action, const int& pin);
|
||||||
|
|
||||||
void onConfigUpdateReceived(const char* topic, const char* value);
|
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 onKeypadCommandReceived(const char* command, const uint& id, const String& name, const String& code, const int& enabled);
|
||||||
|
void onTimeControlCommandReceived(const char* value);
|
||||||
|
|
||||||
void updateKeyTurnerState();
|
void updateKeyTurnerState();
|
||||||
void updateBatteryState();
|
void updateBatteryState();
|
||||||
void updateConfig();
|
void updateConfig();
|
||||||
void updateAuthData();
|
void updateAuthData();
|
||||||
void updateKeypad();
|
void updateKeypad();
|
||||||
|
void updateTimeControl();
|
||||||
void postponeBleWatchdog();
|
void postponeBleWatchdog();
|
||||||
|
|
||||||
void updateGpioOutputs();
|
void updateGpioOutputs();
|
||||||
@@ -85,6 +88,7 @@ private:
|
|||||||
bool _publishAuthData = false;
|
bool _publishAuthData = false;
|
||||||
bool _clearAuthData = false;
|
bool _clearAuthData = false;
|
||||||
std::vector<uint16_t> _keypadCodeIds;
|
std::vector<uint16_t> _keypadCodeIds;
|
||||||
|
std::vector<uint8_t> _timeControlIds;
|
||||||
|
|
||||||
NukiLock::KeyTurnerState _lastKeyTurnerState;
|
NukiLock::KeyTurnerState _lastKeyTurnerState;
|
||||||
NukiLock::KeyTurnerState _keyTurnerState;
|
NukiLock::KeyTurnerState _keyTurnerState;
|
||||||
|
|||||||
@@ -48,6 +48,8 @@
|
|||||||
#define preference_admin_enabled "aclConfig"
|
#define preference_admin_enabled "aclConfig"
|
||||||
#define preference_keypad_info_enabled "kpInfoEnabled"
|
#define preference_keypad_info_enabled "kpInfoEnabled"
|
||||||
#define preference_keypad_control_enabled "kpCntrlEnabled"
|
#define preference_keypad_control_enabled "kpCntrlEnabled"
|
||||||
|
#define preference_timecontrol_control_enabled "tcCntrlEnabled"
|
||||||
|
#define preference_timecontrol_info_enabled "tcInfoEnabled"
|
||||||
#define preference_publish_authdata "pubAuth"
|
#define preference_publish_authdata "pubAuth"
|
||||||
#define preference_acl "aclLckOpn"
|
#define preference_acl "aclLckOpn"
|
||||||
#define preference_register_as_app "regAsApp" // true = register as hub; false = register as app
|
#define preference_register_as_app "regAsApp" // true = register as hub; false = register as app
|
||||||
@@ -77,9 +79,10 @@ private:
|
|||||||
preference_ip_dhcp_enabled, preference_ip_address, preference_ip_subnet, preference_ip_gateway, preference_ip_dns_server,
|
preference_ip_dhcp_enabled, preference_ip_address, preference_ip_subnet, preference_ip_gateway, preference_ip_dns_server,
|
||||||
preference_network_hardware, preference_network_wifi_fallback_disabled, preference_rssi_publish_interval,
|
preference_network_hardware, preference_network_wifi_fallback_disabled, preference_rssi_publish_interval,
|
||||||
preference_hostname, preference_network_timeout, preference_restart_on_disconnect,
|
preference_hostname, preference_network_timeout, preference_restart_on_disconnect,
|
||||||
preference_restart_ble_beacon_lost, preference_query_interval_lockstate,
|
preference_restart_ble_beacon_lost, preference_query_interval_lockstate,
|
||||||
preference_query_interval_configuration, preference_query_interval_battery, preference_query_interval_keypad,
|
preference_query_interval_configuration, preference_query_interval_battery, preference_query_interval_keypad,
|
||||||
preference_keypad_control_enabled, preference_admin_enabled, preference_keypad_info_enabled, preference_acl,
|
preference_keypad_control_enabled, preference_admin_enabled, preference_keypad_info_enabled, preference_acl,
|
||||||
|
preference_timecontrol_control_enabled, preference_timecontrol_info_enabled,
|
||||||
preference_access_level, preference_register_as_app, preference_command_nr_of_retries,
|
preference_access_level, preference_register_as_app, preference_command_nr_of_retries,
|
||||||
preference_command_retry_delay, preference_cred_user, preference_cred_password, preference_publish_authdata,
|
preference_command_retry_delay, preference_cred_user, preference_cred_password, preference_publish_authdata,
|
||||||
preference_publish_debug_info, preference_presence_detection_timeout,
|
preference_publish_debug_info, preference_presence_detection_timeout,
|
||||||
@@ -96,7 +99,7 @@ private:
|
|||||||
{
|
{
|
||||||
preference_started_before, preference_mqtt_log_enabled, preference_check_updates, preference_lock_enabled, preference_opener_enabled, preference_opener_continuous_mode,
|
preference_started_before, preference_mqtt_log_enabled, preference_check_updates, preference_lock_enabled, preference_opener_enabled, preference_opener_continuous_mode,
|
||||||
preference_restart_on_disconnect, preference_keypad_control_enabled, preference_admin_enabled, preference_keypad_info_enabled,
|
preference_restart_on_disconnect, preference_keypad_control_enabled, preference_admin_enabled, preference_keypad_info_enabled,
|
||||||
preference_register_as_app, preference_ip_dhcp_enabled,
|
preference_timecontrol_control_enabled, preference_timecontrol_info_enabled, preference_register_as_app, preference_ip_dhcp_enabled,
|
||||||
preference_publish_authdata, preference_has_mac_saved, preference_publish_debug_info, preference_network_wifi_fallback_disabled
|
preference_publish_authdata, preference_has_mac_saved, preference_publish_debug_info, preference_network_wifi_fallback_disabled
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
30
README.md
30
README.md
@@ -151,6 +151,8 @@ In a browser navigate to the IP address assigned to the ESP32.
|
|||||||
- Change Lock/Opener configuration: Allows changing the Nuki Lock/Opener configuration through MQTT.
|
- Change Lock/Opener configuration: Allows changing the Nuki Lock/Opener configuration through MQTT.
|
||||||
- Publish keypad codes information (Only available when a Keypad is detected): Enable to publish information about keypad codes through MQTT, see the "Keypad control" section of this README
|
- Publish keypad codes information (Only available when a Keypad is detected): Enable to publish information about keypad codes through MQTT, see the "Keypad control" section of this README
|
||||||
- Add, modify and delete keypad codes (Only available when a Keypad is detected): Enable to allow configuration of keypad codes through MQTT, see the "Keypad control" section of this README
|
- Add, modify and delete keypad codes (Only available when a Keypad is detected): Enable to allow configuration of keypad codes through MQTT, see the "Keypad control" section of this README
|
||||||
|
- Publish time control information: Enable to publish information about time control entries through MQTT, see the "Time control" section of this README
|
||||||
|
- Add, modify and delete time control entries: Enable to allow configuration of time control entries through MQTT, see the "Time control" section of this README
|
||||||
- Publish auth data: Enable to publish authorization data to the MQTT topic lock/log. Requires the Nuki security code / PIN to be set, see "Nuki Lock PIN / Nuki Opener PIN" below.
|
- Publish auth data: Enable to publish authorization data to the MQTT topic lock/log. Requires the Nuki security code / PIN to be set, see "Nuki Lock PIN / Nuki Opener PIN" below.
|
||||||
|
|
||||||
#### Nuki Lock/Opener Access Control
|
#### Nuki Lock/Opener Access Control
|
||||||
@@ -252,6 +254,10 @@ In a browser navigate to the IP address assigned to the ESP32.
|
|||||||
|
|
||||||
- See the "Keypad control" section of this README.
|
- See the "Keypad control" section of this README.
|
||||||
|
|
||||||
|
### Time Control
|
||||||
|
|
||||||
|
- See the "Time control" section of this README.
|
||||||
|
|
||||||
### Info
|
### Info
|
||||||
|
|
||||||
- info/nukiHubVersion: Set to the current version number of the Nuki Hub firmware.
|
- info/nukiHubVersion: Set to the current version number of the Nuki Hub firmware.
|
||||||
@@ -343,6 +349,30 @@ For example, to add a code:
|
|||||||
- write 1 to enabled
|
- write 1 to enabled
|
||||||
- write "add" to action
|
- write "add" to action
|
||||||
|
|
||||||
|
## Time control using JSON (optional)
|
||||||
|
|
||||||
|
Time control entries can be added, updated and removed. This has to enabled first in the configuration portal. Check "Add, modify and delete time control entries" under "Access Level Configuration" and save the configuration.
|
||||||
|
|
||||||
|
Information about current time control entries is published as JSON data to the "timecontrol/json" MQTT topic.<br>
|
||||||
|
This needs to be enabled separately by checking "Publish time control entries information" under "Access Level Configuration" and saving the configuration.
|
||||||
|
|
||||||
|
To change Nuki Lock/Opener time control settings set the `timecontrol/actionJson` topic to a JSON formatted value containing the following nodes.
|
||||||
|
|
||||||
|
| Node | Delete | Add | Update | Usage | Possible values |
|
||||||
|
|------------------|----------|----------|----------|------------------------------------------------------------------------------------------|----------------------------------------------------------------|
|
||||||
|
| action | Required | Required | Required | The action to execute | "delete", "add", "update" |
|
||||||
|
| entryId | Required | Not used | Required | The entry ID of the existing entry to delete or update | Integer |
|
||||||
|
| enabled | Not used | Not used | Optional | Enable or disable the entry, enabled if not set | 1 = enabled, 0 = disabled |
|
||||||
|
| weekdays | Not used | Optional | Optional | Weekdays on which the chosen lock action should be exectued | Array of days: "mon", "tue", "wed", "thu" , "fri" "sat", "sun" |
|
||||||
|
| time | Not used | Required | Required | The time on which the chosen lock action should be executed | "HH:MM" |
|
||||||
|
| lockaction | Not used | Required | Required | The lock action that should be executed on the chosen weekdays at the chosen time | For the Nuki lock: "Unlock", "Lock", "Unlatch", "LockNgo", "LockNgoUnlatch", "FullLock", "FobAction1", "FobAction2", "FobAction3. For the Nuki Opener: "ActivateRTO", "DeactivateRTO", "ElectricStrikeActuation", "ActivateCM", "DeactivateCM", "FobAction1", "FobAction2", "FobAction3" |
|
||||||
|
|
||||||
|
Example usage:<br>
|
||||||
|
Examples:
|
||||||
|
- Delete: `{ "action": "delete", "entryId": "1234" }`
|
||||||
|
- Add: `{ "action": "add", "weekdays": [ "wed", "thu", "fri" ], "time": "08:00", "lockaction": "unlock" }`
|
||||||
|
- Update: `{ "action": "update", "entryId": "1234", "enabled": "1", "weekdays": [ "mon", "tue", "sat", "sun" ], "time": "08:00", "lockaction": "lock" }`
|
||||||
|
|
||||||
## GPIO lock control (optional)
|
## GPIO lock control (optional)
|
||||||
|
|
||||||
The lock can be controlled via GPIO.<br>
|
The lock can be controlled via GPIO.<br>
|
||||||
|
|||||||
@@ -480,6 +480,16 @@ bool WebCfgServer::processArgs(String& message)
|
|||||||
_preferences->putBool(preference_keypad_control_enabled, (value == "1"));
|
_preferences->putBool(preference_keypad_control_enabled, (value == "1"));
|
||||||
configChanged = true;
|
configChanged = true;
|
||||||
}
|
}
|
||||||
|
else if(key == "TCPUB")
|
||||||
|
{
|
||||||
|
_preferences->putBool(preference_timecontrol_info_enabled, (value == "1"));
|
||||||
|
configChanged = true;
|
||||||
|
}
|
||||||
|
else if(key == "TCENA")
|
||||||
|
{
|
||||||
|
_preferences->putBool(preference_timecontrol_control_enabled, (value == "1"));
|
||||||
|
configChanged = true;
|
||||||
|
}
|
||||||
else if(key == "PUBAUTH")
|
else if(key == "PUBAUTH")
|
||||||
{
|
{
|
||||||
_preferences->putBool(preference_publish_authdata, (value == "1"));
|
_preferences->putBool(preference_publish_authdata, (value == "1"));
|
||||||
@@ -944,6 +954,9 @@ void WebCfgServer::buildAccLvlHtml(String &response)
|
|||||||
printCheckBox(response, "KPPUB", "Publish keypad codes information", _preferences->getBool(preference_keypad_info_enabled));
|
printCheckBox(response, "KPPUB", "Publish keypad codes information", _preferences->getBool(preference_keypad_info_enabled));
|
||||||
printCheckBox(response, "KPENA", "Add, modify and delete keypad codes", _preferences->getBool(preference_keypad_control_enabled));
|
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, "TCENA", "Add, modify and delete time control entries", _preferences->getBool(preference_timecontrol_control_enabled));
|
||||||
printCheckBox(response, "PUBAUTH", "Publish authorisation log (may reduce battery life)", _preferences->getBool(preference_publish_authdata));
|
printCheckBox(response, "PUBAUTH", "Publish authorisation log (may reduce battery life)", _preferences->getBool(preference_publish_authdata));
|
||||||
response.concat("</table><br>");
|
response.concat("</table><br>");
|
||||||
if(_nuki != nullptr)
|
if(_nuki != nullptr)
|
||||||
|
|||||||
Reference in New Issue
Block a user