From 72289336ad984195dce7f022997785367ab09df7 Mon Sep 17 00:00:00 2001 From: iranl Date: Sun, 26 May 2024 21:45:54 +0200 Subject: [PATCH] Auth log --- README.md | 1 + src/MqttTopics.h | 1 + src/NetworkLock.cpp | 132 ++++++++++++++-------------- src/NetworkOpener.cpp | 176 +++++++++++++++++++------------------- src/NukiOpenerWrapper.cpp | 24 ++++-- src/NukiWrapper.cpp | 22 +++-- 6 files changed, 181 insertions(+), 175 deletions(-) diff --git a/README.md b/README.md index d9ad064..aa62953 100644 --- a/README.md +++ b/README.md @@ -200,6 +200,7 @@ In a browser navigate to the IP address assigned to the ESP32. - lock/trigger: The trigger of the last action: autoLock, automatic, button, manual, system. - lock/lastLockAction: Reports the last lock action as a string. Possible values are: Unlock, Lock, Unlatch, LockNgo, LockNgoUnlatch, FullLock, FobAction1, FobAction2, FobAction3, Unknown. - lock/log: If "Publish auth data" is enabled in the web interface, this topic will be filled with the log of authorization data. +- lock/shortLog: If "Publish auth data" is enabled in the web interface, this topic will be filled with the 3 most recent entries in the log of authorization data, updates faster than lock/log. - lock/completionStatus: Status of the last action as reported by Nuki Lock: success, motorBlocked, canceled, tooRecent, busy, lowMotorVoltage, clutchFailure, motorPowerFailure, incompleteFailure, invalidCode, otherError, unknown. - lock/authorizationId: If enabled in the web interface, this node returns the authorization id of the last lock action. - lock/authorizationName: If enabled in the web interface, this node returns the authorization name of the last lock action. diff --git a/src/MqttTopics.h b/src/MqttTopics.h index bb38f22..af639a2 100644 --- a/src/MqttTopics.h +++ b/src/MqttTopics.h @@ -12,6 +12,7 @@ #define mqtt_topic_lock_trigger "/lock/trigger" #define mqtt_topic_lock_last_lock_action "/lock/lastLockAction" #define mqtt_topic_lock_log "/lock/log" +#define mqtt_topic_lock_log_latest "/lock/shortLog" #define mqtt_topic_lock_auth_id "/lock/authorizationId" #define mqtt_topic_lock_auth_name "/lock/authorizationName" #define mqtt_topic_lock_completionStatus "/lock/completionStatus" diff --git a/src/NetworkLock.cpp b/src/NetworkLock.cpp index 2f79b7a..2b43924 100644 --- a/src/NetworkLock.cpp +++ b/src/NetworkLock.cpp @@ -429,83 +429,79 @@ void NetworkLock::publishAuthorizationInfo(const std::list& } } - if(!latest) + auto entry = json.add(); + + entry["index"] = log.index; + entry["authorizationId"] = log.authId; + entry["authorizationName"] = authName; + entry["timeYear"] = log.timeStampYear; + entry["timeMonth"] = log.timeStampMonth; + entry["timeDay"] = log.timeStampDay; + entry["timeHour"] = log.timeStampHour; + entry["timeMinute"] = log.timeStampMinute; + entry["timeSecond"] = log.timeStampSecond; + + memset(str, 0, sizeof(str)); + loggingTypeToString(log.loggingType, str); + entry["type"] = str; + + switch(log.loggingType) { - auto entry = json.add(); + case NukiLock::LoggingType::LockAction: + memset(str, 0, sizeof(str)); + NukiLock::lockactionToString((NukiLock::LockAction)log.data[0], str); + entry["action"] = str; - entry["index"] = log.index; - entry["authorizationId"] = log.authId; - entry["authorizationName"] = authName; - entry["timeYear"] = log.timeStampYear; - entry["timeMonth"] = log.timeStampMonth; - entry["timeDay"] = log.timeStampDay; - entry["timeHour"] = log.timeStampHour; - entry["timeMinute"] = log.timeStampMinute; - entry["timeSecond"] = log.timeStampSecond; + memset(str, 0, sizeof(str)); + NukiLock::triggerToString((NukiLock::Trigger)log.data[1], str); + entry["trigger"] = str; - memset(str, 0, sizeof(str)); - loggingTypeToString(log.loggingType, str); - entry["type"] = str; + memset(str, 0, sizeof(str)); + NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[3], str); + entry["completionStatus"] = str; + entry["completionStatusVal"] = log.data[3]; + break; + case NukiLock::LoggingType::KeypadAction: + memset(str, 0, sizeof(str)); + NukiLock::lockactionToString((NukiLock::LockAction)log.data[0], str); + entry["action"] = str; - switch(log.loggingType) - { - case NukiLock::LoggingType::LockAction: - memset(str, 0, sizeof(str)); - NukiLock::lockactionToString((NukiLock::LockAction)log.data[0], str); - entry["action"] = str; + memset(str, 0, sizeof(str)); + NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[2], str); + entry["completionStatus"] = str; + entry["completionStatusVal"] = log.data[2]; + break; + case NukiLock::LoggingType::DoorSensor: + memset(str, 0, sizeof(str)); + NukiLock::lockactionToString((NukiLock::LockAction)log.data[0], str); - memset(str, 0, sizeof(str)); - NukiLock::triggerToString((NukiLock::Trigger)log.data[1], str); - entry["trigger"] = str; + switch(log.data[0]) + { + case 0: + entry["action"] = "DoorOpened"; + break; + case 1: + entry["action"] = "DoorClosed"; + break; + case 2: + entry["action"] = "SensorJammed"; + break; + default: + entry["action"] = "Unknown"; + break; + } - memset(str, 0, sizeof(str)); - NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[3], str); - entry["completionStatus"] = str; - entry["completionStatusVal"] = log.data[3]; - break; - case NukiLock::LoggingType::KeypadAction: - memset(str, 0, sizeof(str)); - NukiLock::lockactionToString((NukiLock::LockAction)log.data[0], str); - entry["action"] = str; - - memset(str, 0, sizeof(str)); - NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[2], str); - entry["completionStatus"] = str; - entry["completionStatusVal"] = log.data[2]; - break; - case NukiLock::LoggingType::DoorSensor: - memset(str, 0, sizeof(str)); - NukiLock::lockactionToString((NukiLock::LockAction)log.data[0], str); - - switch(log.data[0]) - { - case 0: - entry["action"] = "DoorOpened"; - break; - case 1: - entry["action"] = "DoorClosed"; - break; - case 2: - entry["action"] = "SensorJammed"; - break; - default: - entry["action"] = "Unknown"; - break; - } - - memset(str, 0, sizeof(str)); - NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[2], str); - entry["completionStatus"] = str; - break; - } + memset(str, 0, sizeof(str)); + NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[2], str); + entry["completionStatus"] = str; + break; } } - if(!latest) - { - serializeJson(json, _buffer, _bufferSize); - publishString(mqtt_topic_lock_log, _buffer); - } + serializeJson(json, _buffer, _bufferSize); + + if(latest) publishString(mqtt_topic_lock_log_latest, _buffer); + else publishString(mqtt_topic_lock_log, _buffer); if(authFound) { diff --git a/src/NetworkOpener.cpp b/src/NetworkOpener.cpp index 370fe10..deb4642 100644 --- a/src/NetworkOpener.cpp +++ b/src/NetworkOpener.cpp @@ -398,106 +398,102 @@ void NetworkOpener::publishAuthorizationInfo(const std::list(); + + entry["index"] = log.index; + entry["authorizationId"] = log.authId; + entry["authorizationName"] = _authName; + entry["timeYear"] = log.timeStampYear; + entry["timeMonth"] = log.timeStampMonth; + entry["timeDay"] = log.timeStampDay; + entry["timeHour"] = log.timeStampHour; + entry["timeMinute"] = log.timeStampMinute; + entry["timeSecond"] = log.timeStampSecond; + + memset(str, 0, sizeof(str)); + loggingTypeToString(log.loggingType, str); + entry["type"] = str; + + switch(log.loggingType) { - auto entry = json.add(); + case NukiOpener::LoggingType::LockAction: + memset(str, 0, sizeof(str)); + NukiOpener::lockactionToString((NukiOpener::LockAction)log.data[0], str); + entry["action"] = str; - entry["index"] = log.index; - entry["authorizationId"] = log.authId; - entry["authorizationName"] = _authName; - entry["timeYear"] = log.timeStampYear; - entry["timeMonth"] = log.timeStampMonth; - entry["timeDay"] = log.timeStampDay; - entry["timeHour"] = log.timeStampHour; - entry["timeMinute"] = log.timeStampMinute; - entry["timeSecond"] = log.timeStampSecond; + memset(str, 0, sizeof(str)); + NukiOpener::triggerToString((NukiOpener::Trigger)log.data[1], str); + entry["trigger"] = str; - memset(str, 0, sizeof(str)); - loggingTypeToString(log.loggingType, str); - entry["type"] = str; + memset(str, 0, sizeof(str)); + NukiOpener::completionStatusToString((NukiOpener::CompletionStatus)log.data[3], str); + entry["completionStatus"] = str; + break; + case NukiOpener::LoggingType::KeypadAction: + memset(str, 0, sizeof(str)); + NukiOpener::lockactionToString((NukiOpener::LockAction)log.data[0], str); + entry["action"] = str; - switch(log.loggingType) - { - case NukiOpener::LoggingType::LockAction: - memset(str, 0, sizeof(str)); - NukiOpener::lockactionToString((NukiOpener::LockAction)log.data[0], str); - entry["action"] = str; + memset(str, 0, sizeof(str)); + NukiOpener::completionStatusToString((NukiOpener::CompletionStatus)log.data[2], str); + entry["completionStatus"] = str; + break; + case NukiOpener::LoggingType::DoorbellRecognition: + switch(log.data[0] & 3) + { + case 0: + entry["mode"] = "None"; + break; + case 1: + entry["mode"] = "RTO"; + break; + case 2: + entry["mode"] = "CM"; + break; + default: + entry["mode"] = "Unknown"; + break; + } - memset(str, 0, sizeof(str)); - NukiOpener::triggerToString((NukiOpener::Trigger)log.data[1], str); - entry["trigger"] = str; + switch(log.data[1]) + { + case 0: + entry["source"] = "Doorbell"; + break; + case 1: + entry["source"] = "Timecontrol"; + break; + case 2: + entry["source"] = "App"; + break; + case 3: + entry["source"] = "Button"; + break; + case 4: + entry["source"] = "Fob"; + break; + case 5: + entry["source"] = "Bridge"; + break; + case 6: + entry["source"] = "Keypad"; + break; + default: + entry["source"] = "Unknown"; + break; } - memset(str, 0, sizeof(str)); - NukiOpener::completionStatusToString((NukiOpener::CompletionStatus)log.data[3], str); - entry["completionStatus"] = str; - break; - case NukiOpener::LoggingType::KeypadAction: - memset(str, 0, sizeof(str)); - NukiOpener::lockactionToString((NukiOpener::LockAction)log.data[0], str); - entry["action"] = str; + entry["geofence"] = log.data[2] == 1 ? "active" : "inactive"; + entry["doorbellSuppression"] = log.data[3] == 1 ? "active" : "inactive"; + entry["completionStatus"] = str; - memset(str, 0, sizeof(str)); - NukiOpener::completionStatusToString((NukiOpener::CompletionStatus)log.data[2], str); - entry["completionStatus"] = str; - break; - case NukiOpener::LoggingType::DoorbellRecognition: - switch(log.data[0] & 3) - { - case 0: - entry["mode"] = "None"; - break; - case 1: - entry["mode"] = "RTO"; - break; - case 2: - entry["mode"] = "CM"; - break; - default: - entry["mode"] = "Unknown"; - break; - } - - switch(log.data[1]) - { - case 0: - entry["source"] = "Doorbell"; - break; - case 1: - entry["source"] = "Timecontrol"; - break; - case 2: - entry["source"] = "App"; - break; - case 3: - entry["source"] = "Button"; - break; - case 4: - entry["source"] = "Fob"; - break; - case 5: - entry["source"] = "Bridge"; - break; - case 6: - entry["source"] = "Keypad"; - break; - default: - entry["source"] = "Unknown"; - break; } - - entry["geofence"] = log.data[2] == 1 ? "active" : "inactive"; - entry["doorbellSuppression"] = log.data[3] == 1 ? "active" : "inactive"; - entry["completionStatus"] = str; - - break; - } + break; } } - if(!latest) - { - serializeJson(json, _buffer, _bufferSize); - publishString(mqtt_topic_lock_log, _buffer); - } + serializeJson(json, _buffer, _bufferSize); + + if(latest) publishString(mqtt_topic_lock_log_latest, _buffer); + else publishString(mqtt_topic_lock_log, _buffer); if(authFound) { diff --git a/src/NukiOpenerWrapper.cpp b/src/NukiOpenerWrapper.cpp index d99ab88..648108e 100644 --- a/src/NukiOpenerWrapper.cpp +++ b/src/NukiOpenerWrapper.cpp @@ -499,22 +499,28 @@ void NukiOpenerWrapper::updateAuthData(bool retrieved) if(!retrieved) { - Nuki::CmdResult result = _nukiOpener.retrieveLogEntries(0, 3, 1, false); + delay(250); + Nuki::CmdResult result = _nukiOpener.retrieveLogEntries(0, _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 1, false); Log->print(F("Retrieve log entries: ")); Log->println(result); printCommandResult(result); if(result == Nuki::CmdResult::Success) { - Nuki::CmdResult result = _nukiOpener.retrieveLogEntries(0, _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 1, false); - if(result == Nuki::CmdResult::Success) - { - _waitAuthLogUpdateTs = millis() + 5000; - } - delay(150); + _waitAuthLogUpdateTs = millis() + 5000; + delay(100); std::list log; _nukiOpener.getLogEntries(&log); - _network->publishAuthorizationInfo(log, true); + + if(log.size() > _preferences->getInt(preference_authlog_max_entries, 3)) + { + log.resize(_preferences->getInt(preference_authlog_max_entries, 3)); + } + + if(log.size() > 0) + { + _network->publishAuthorizationInfo(log, true); + } } } else @@ -1734,7 +1740,7 @@ void NukiOpenerWrapper::onKeypadJsonCommandReceived(const char *value) _network->publishKeypadJsonCommandResult("noExistingCodeIdSet"); return; } - + NukiOpener::UpdatedKeypadEntry entry; memset(&entry, 0, sizeof(entry)); entry.codeId = codeId; diff --git a/src/NukiWrapper.cpp b/src/NukiWrapper.cpp index 87f5b5d..e923680 100644 --- a/src/NukiWrapper.cpp +++ b/src/NukiWrapper.cpp @@ -480,22 +480,28 @@ void NukiWrapper::updateAuthData(bool retrieved) if(!retrieved) { - Nuki::CmdResult result = _nukiLock.retrieveLogEntries(0, 3, 1, false); + delay(250); + Nuki::CmdResult result = _nukiLock.retrieveLogEntries(0, _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 1, false); Log->print(F("Retrieve log entries: ")); Log->println(result); printCommandResult(result); if(result == Nuki::CmdResult::Success) { - Nuki::CmdResult result = _nukiLock.retrieveLogEntries(0, _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 1, false); - if(result == Nuki::CmdResult::Success) - { - _waitAuthLogUpdateTs = millis() + 5000; - } - delay(150); + _waitAuthLogUpdateTs = millis() + 5000; + delay(100); std::list log; _nukiLock.getLogEntries(&log); - _network->publishAuthorizationInfo(log, true); + + if(log.size() > _preferences->getInt(preference_authlog_max_entries, 3)) + { + log.resize(_preferences->getInt(preference_authlog_max_entries, 3)); + } + + if(log.size() > 0) + { + _network->publishAuthorizationInfo(log, true); + } } } else