Publish keypad code and rolling log

This commit is contained in:
iranl
2024-05-30 19:36:23 +02:00
parent ff741f7989
commit 58ec4b345c
17 changed files with 213 additions and 131 deletions

View File

@@ -13,6 +13,8 @@
#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_log_rolling "/lock/rollingLog"
#define mqtt_topic_lock_log_rolling_last "lock/lastRollingLog"
#define mqtt_topic_lock_auth_id "/lock/authorizationId"
#define mqtt_topic_lock_auth_name "/lock/authorizationName"
#define mqtt_topic_lock_completionStatus "/lock/completionStatus"

View File

@@ -3023,6 +3023,27 @@ void Network::publishHASSConfigAccessLog(char *deviceType, const char *baseTopic
"",
{ { (char*)"ic", (char*)"mdi:format-list-bulleted" },
{ (char*)"val_tpl", (char*)"{{ (value_json|selectattr('type', 'eq', 'LockAction')|selectattr('action', 'in', ['Lock', 'Unlock', 'Unlatch'])|first|default).authorizationName|default }}" }});
String rollingSate = "~";
rollingSate.concat(mqtt_topic_lock_log_rolling);
const char *rollingStateChr = rollingSate.c_str();
publishHassTopic("sensor",
"rolling_log",
uidString,
"_rolling_log",
"Rolling authorization log",
name,
baseTopic,
String("~") + mqtt_topic_lock_log_rolling,
deviceType,
"",
"",
"diagnostic",
"",
{ { (char*)"ic", (char*)"mdi:format-list-bulleted" },
{ (char*)"json_attr_t", (char*)rollingStateChr },
{ (char*)"val_tpl", (char*)"{{value_json.authorizationId}}" }});
}
void Network::publishHASSConfigKeypad(char *deviceType, const char *baseTopic, char *name, char *uidString)
@@ -3194,6 +3215,7 @@ void Network::removeHASSConfig(char* uidString)
removeHassTopic((char*)"sensor", (char*)"sound_level", uidString);
removeHassTopic((char*)"sensor", (char*)"last_action_authorization", uidString);
removeHassTopic((char*)"sensor", (char*)"keypad_status", uidString);
removeHassTopic((char*)"sensor", (char*)"rolling_log", uidString);
removeHassTopic((char*)"sensor", (char*)"wifi_signal_strength", uidString);
removeHassTopic((char*)"sensor", (char*)"bluetooth_signal_strength", uidString);
removeHassTopic((char*)"binary_sensor", (char*)"continuous_mode", uidString);

View File

@@ -116,6 +116,11 @@ void NetworkLock::initialize()
_network->initTopic(_mqttPath, mqtt_topic_timecontrol_action, "--");
}
if(_preferences->getBool(preference_publish_authdata, false))
{
_network->subscribe(_mqttPath, mqtt_topic_lock_log_rolling_last);
}
_network->addReconnectedCallback([&]()
{
_reconnected = true;
@@ -157,6 +162,13 @@ void NetworkLock::onMqttDataReceived(const char* topic, byte* payload, const uns
delay(200);
restartEsp(RestartReason::RequestedViaMqtt);
}
else if(comparePrefixedPath(topic, mqtt_topic_lock_log_rolling_last))
{
if(strcmp(value, "") == 0 ||
strcmp(value, "--") == 0) return;
if(atoi(value) > 0 && atoi(value) > _lastRollingLog) _lastRollingLog = atoi(value);
}
if(comparePrefixedPath(topic, mqtt_topic_lock_action))
{
@@ -394,7 +406,7 @@ void NetworkLock::publishKeyTurnerState(const NukiLock::KeyTurnerState& keyTurne
serializeJson(json, _buffer, _bufferSize);
publishString(mqtt_topic_lock_json, _buffer);
serializeJson(jsonBattery, _buffer, _bufferSize);
publishString(mqtt_topic_battery_basic_json, _buffer);
@@ -439,7 +451,7 @@ void NetworkLock::publishAuthorizationInfo(const std::list<NukiLock::LogEntry>&
{
char str[50];
char authName[33];
bool authFound = false;
uint32_t authIndex = 0;
JsonDocument json;
@@ -454,9 +466,9 @@ void NetworkLock::publishAuthorizationInfo(const std::list<NukiLock::LogEntry>&
memcpy(authName, log.name, sizeName);
if(authName[sizeName - 1] != '\0') authName[sizeName] = '\0';
if(!authFound)
if(log.index > authIndex)
{
authFound = true;
authIndex = log.index;
_authFound = true;
_authId = log.authId;
memset(_authName, 0, sizeof(_authName));
@@ -531,6 +543,14 @@ void NetworkLock::publishAuthorizationInfo(const std::list<NukiLock::LogEntry>&
entry["completionStatus"] = str;
break;
}
if(log.index > _lastRollingLog)
{
_lastRollingLog = log.index;
serializeJson(entry, _buffer, _bufferSize);
publishString(mqtt_topic_lock_log_rolling, _buffer);
publishInt(mqtt_topic_lock_log_rolling_last, log.index);
}
}
serializeJson(json, _buffer, _bufferSize);
@@ -538,7 +558,7 @@ void NetworkLock::publishAuthorizationInfo(const std::list<NukiLock::LogEntry>&
if(latest) publishString(mqtt_topic_lock_log_latest, _buffer);
else publishString(mqtt_topic_lock_log, _buffer);
if(authFound)
if(authIndex > 0)
{
publishUInt(mqtt_topic_lock_auth_id, _authId);
publishString(mqtt_topic_lock_auth_name, _authName);
@@ -735,6 +755,12 @@ void NetworkLock::publishKeypad(const std::list<NukiLock::KeypadEntry>& entries,
auto jsonEntry = json.add<JsonVariant>();
jsonEntry["codeId"] = entry.codeId;
if(_preferences->getBool(preference_keypad_publish_code, false))
{
jsonEntry["code"] = entry.code;
}
jsonEntry["enabled"] = entry.enabled;
jsonEntry["name"] = entry.name;
char createdDT[20];
@@ -826,6 +852,19 @@ void NetworkLock::publishKeypad(const std::list<NukiLock::KeypadEntry>& entries,
++index;
}
if(!_preferences->getBool(preference_keypad_publish_code, false))
{
for(int i=0; i<maxKeypadCodeCount; i++)
{
String codeTopic = _mqttPath;
codeTopic.concat(mqtt_topic_keypad);
codeTopic.concat("/code_");
codeTopic.concat(std::to_string(i).c_str());
codeTopic.concat("/");
_network->removeTopic(codeTopic, "code");
}
}
}
else if (maxKeypadCodeCount > 0)
{
@@ -838,6 +877,7 @@ void NetworkLock::publishKeypad(const std::list<NukiLock::KeypadEntry>& entries,
codeTopic.concat("/");
_network->removeTopic(codeTopic, "id");
_network->removeTopic(codeTopic, "enabled");
_network->removeTopic(codeTopic, "code");
_network->removeTopic(codeTopic, "name");
_network->removeTopic(codeTopic, "createdYear");
_network->removeTopic(codeTopic, "createdMonth");
@@ -1028,6 +1068,7 @@ void NetworkLock::publishHASSConfig(char *deviceType, const char *baseTopic, cha
else
{
_network->removeHASSConfigTopic((char*)"sensor", (char*)"last_action_authorization", uidString);
_network->removeHASSConfigTopic((char*)"sensor", (char*)"rolling_log", uidString);
}
if(hasKeypad)
@@ -1098,6 +1139,12 @@ void NetworkLock::publishKeypadEntry(const String topic, NukiLock::KeypadEntry e
publishInt(concat(topic, "/id").c_str(), entry.codeId);
publishBool(concat(topic, "/enabled").c_str(), entry.enabled);
publishString(concat(topic, "/name").c_str(), codeName);
if(_preferences->getBool(preference_keypad_publish_code, false))
{
publishInt(concat(topic, "/code").c_str(), entry.code);
}
publishInt(concat(topic, "/createdYear").c_str(), entry.dateCreatedYear);
publishInt(concat(topic, "/createdMonth").c_str(), entry.dateCreatedMonth);
publishInt(concat(topic, "/createdDay").c_str(), entry.dateCreatedDay);

View File

@@ -92,6 +92,7 @@ private:
uint32_t _authId = 0;
char _authName[33];
bool _authFound = false;
uint32_t _lastRollingLog = 0;
char* _buffer;
size_t _bufferSize;

View File

@@ -97,6 +97,11 @@ void NetworkOpener::initialize()
_network->initTopic(_mqttPath, mqtt_topic_timecontrol_action, "--");
}
if(_preferences->getBool(preference_publish_authdata, false))
{
_network->subscribe(_mqttPath, mqtt_topic_lock_log_rolling_last);
}
_network->addReconnectedCallback([&]()
{
_reconnected = true;
@@ -116,6 +121,14 @@ void NetworkOpener::onMqttDataReceived(const char* topic, byte* payload, const u
{
char* value = (char*)payload;
if(comparePrefixedPath(topic, mqtt_topic_lock_log_rolling_last))
{
if(strcmp(value, "") == 0 ||
strcmp(value, "--") == 0) return;
if(atoi(value) > 0 && atoi(value) > _lastRollingLog) _lastRollingLog = atoi(value);
}
if(comparePrefixedPath(topic, mqtt_topic_lock_action))
{
if(strcmp(value, "") == 0 ||
@@ -406,7 +419,7 @@ void NetworkOpener::publishAuthorizationInfo(const std::list<NukiOpener::LogEntr
{
char str[50];
char authName[33];
bool authFound = false;
uint32_t authIndex = 0;
JsonDocument json;
@@ -421,9 +434,9 @@ void NetworkOpener::publishAuthorizationInfo(const std::list<NukiOpener::LogEntr
memcpy(authName, log.name, sizeName);
if(authName[sizeName - 1] != '\0') authName[sizeName] = '\0';
if(!authFound)
if(log.index > authIndex)
{
authFound = true;
authIndex = log.index;
_authFound = true;
_authId = log.authId;
memset(_authName, 0, sizeof(_authName));
@@ -521,6 +534,14 @@ void NetworkOpener::publishAuthorizationInfo(const std::list<NukiOpener::LogEntr
break;
}
if(log.index > _lastRollingLog)
{
_lastRollingLog = log.index;
serializeJson(entry, _buffer, _bufferSize);
publishString(mqtt_topic_lock_log_rolling, _buffer);
publishInt(mqtt_topic_lock_log_rolling_last, log.index);
}
}
serializeJson(json, _buffer, _bufferSize);
@@ -528,7 +549,7 @@ void NetworkOpener::publishAuthorizationInfo(const std::list<NukiOpener::LogEntr
if(latest) publishString(mqtt_topic_lock_log_latest, _buffer);
else publishString(mqtt_topic_lock_log, _buffer);
if(authFound)
if(authIndex > 0)
{
publishUInt(mqtt_topic_lock_auth_id, _authId);
publishString(mqtt_topic_lock_auth_name, _authName);
@@ -702,13 +723,23 @@ void NetworkOpener::publishBleAddress(const std::string &address)
publishString(mqtt_topic_lock_address, address);
}
void NetworkOpener::publishHASSConfig(char* deviceType, const char* baseTopic, char* name, char* uidString, char* lockAction, char* unlockAction, char* openAction)
void NetworkOpener::publishHASSConfig(char* deviceType, const char* baseTopic, char* name, char* uidString, const bool& publishAuthData, char* lockAction, char* unlockAction, char* openAction)
{
String availabilityTopic = _preferences->getString("mqttpath");
availabilityTopic.concat("/maintenance/mqttConnectionState");
_network->publishHASSConfig(deviceType, baseTopic, name, uidString, availabilityTopic.c_str(), false, lockAction, unlockAction, openAction);
_network->publishHASSConfigAdditionalOpenerEntities(deviceType, baseTopic, name, uidString);
if(publishAuthData)
{
_network->publishHASSConfigAccessLog(deviceType, baseTopic, name, uidString);
}
else
{
_network->removeHASSConfigTopic((char*)"sensor", (char*)"last_action_authorization", uidString);
_network->removeHASSConfigTopic((char*)"sensor", (char*)"rolling_log", uidString);
}
}
void NetworkOpener::removeHASSConfig(char* uidString)
@@ -734,6 +765,12 @@ void NetworkOpener::publishKeypad(const std::list<NukiLock::KeypadEntry>& entrie
jsonEntry["codeId"] = entry.codeId;
jsonEntry["enabled"] = entry.enabled;
jsonEntry["name"] = entry.name;
if(_preferences->getBool(preference_keypad_publish_code, false))
{
jsonEntry["code"] = entry.code;
}
char createdDT[20];
sprintf(createdDT, "%04d-%02d-%02d %02d:%02d:%02d", entry.dateCreatedYear, entry.dateCreatedMonth, entry.dateCreatedDay, entry.dateCreatedHour, entry.dateCreatedMin, entry.dateCreatedSec);
jsonEntry["dateCreated"] = createdDT;
@@ -823,6 +860,19 @@ void NetworkOpener::publishKeypad(const std::list<NukiLock::KeypadEntry>& entrie
++index;
}
if(!_preferences->getBool(preference_keypad_publish_code, false))
{
for(int i=0; i<maxKeypadCodeCount; i++)
{
String codeTopic = _mqttPath;
codeTopic.concat(mqtt_topic_keypad);
codeTopic.concat("/code_");
codeTopic.concat(std::to_string(i).c_str());
codeTopic.concat("/");
_network->removeTopic(codeTopic, "code");
}
}
}
else if (maxKeypadCodeCount > 0)
{
@@ -835,6 +885,7 @@ void NetworkOpener::publishKeypad(const std::list<NukiLock::KeypadEntry>& entrie
codeTopic.concat("/");
_network->removeTopic(codeTopic, "id");
_network->removeTopic(codeTopic, "enabled");
_network->removeTopic(codeTopic, "code");
_network->removeTopic(codeTopic, "name");
_network->removeTopic(codeTopic, "createdYear");
_network->removeTopic(codeTopic, "createdMonth");
@@ -1025,6 +1076,12 @@ void NetworkOpener::publishKeypadEntry(const String topic, NukiLock::KeypadEntry
publishInt(concat(topic, "/id").c_str(), entry.codeId);
publishBool(concat(topic, "/enabled").c_str(), entry.enabled);
publishString(concat(topic, "/name").c_str(), codeName);
if(_preferences->getBool(preference_keypad_publish_code, false))
{
publishInt(concat(topic, "/code").c_str(), entry.code);
}
publishInt(concat(topic, "/createdYear").c_str(), entry.dateCreatedYear);
publishInt(concat(topic, "/createdMonth").c_str(), entry.dateCreatedMonth);
publishInt(concat(topic, "/createdDay").c_str(), entry.dateCreatedDay);

View File

@@ -31,7 +31,7 @@ public:
void publishRssi(const int& rssi);
void publishRetry(const std::string& message);
void publishBleAddress(const std::string& address);
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, const bool& publishAuthData, char* lockAction, char* unlockAction, char* openAction);
void removeHASSConfig(char* uidString);
void publishKeypad(const std::list<NukiLock::KeypadEntry>& entries, uint maxKeypadCodeCount);
void publishTimeControl(const std::list<NukiOpener::TimeControlEntry>& timeControlEntries);
@@ -71,7 +71,7 @@ private:
void doorbellSuppressionToString(const int dbsupr, char* str);
void soundToString(const int sound, char* str);
void capabilitiesToString(const int capabilities, char* str);
String concat(String a, String b);
Preferences* _preferences;
@@ -93,6 +93,7 @@ private:
uint32_t _authId = 0;
char _authName[33];
bool _authFound = false;
uint32_t _lastRollingLog = 0;
NukiOpener::LockState _currentLockState = NukiOpener::LockState::Undefined;

View File

@@ -333,7 +333,7 @@ void NukiOpenerWrapper::unpair()
Preferences nukiBlePref;
nukiBlePref.begin("NukiHubopener", false);
nukiBlePref.clear();
nukiBlePref.end();
nukiBlePref.end();
_deviceId->assignNewId();
_preferences->remove(preference_nuki_id_opener);
_paired = false;
@@ -521,6 +521,8 @@ void NukiOpenerWrapper::updateAuthData(bool retrieved)
log.resize(_preferences->getInt(preference_authlog_max_entries, 3));
}
log.sort([](const NukiOpener::LogEntry& a, const NukiOpener::LogEntry& b) { return a.index < b.index; });
if(log.size() > 0)
{
_network->publishAuthorizationInfo(log, true);
@@ -537,6 +539,8 @@ void NukiOpenerWrapper::updateAuthData(bool retrieved)
log.resize(_preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG));
}
log.sort([](const NukiOpener::LogEntry& a, const NukiOpener::LogEntry& b) { return a.index < b.index; });
Log->print(F("Log size: "));
Log->println(log.size());
@@ -1359,7 +1363,7 @@ void NukiOpenerWrapper::gpioActionCallback(const GpioAction &action, const int&
void NukiOpenerWrapper::onKeypadCommandReceived(const char *command, const uint &id, const String &name, const String &code, const int& enabled)
{
if(_preferences->getBool(preference_disable_non_json, false)) return;
if(!_preferences->getBool(preference_keypad_control_enabled))
{
_network->publishKeypadCommandResult("KeypadControlDisabled");
@@ -2073,11 +2077,11 @@ void NukiOpenerWrapper::setupHASS()
if(_preferences->getBool(preference_opener_continuous_mode))
{
_network->publishHASSConfig((char*)"Opener", baseTopic.c_str(), (char*)_nukiConfig.name, uidString, (char*)"deactivateCM", (char*)"activateCM", (char*)"electricStrikeActuation");
_network->publishHASSConfig((char*)"Opener", baseTopic.c_str(), (char*)_nukiConfig.name, uidString, _publishAuthData, (char*)"deactivateCM", (char*)"activateCM", (char*)"electricStrikeActuation");
}
else
{
_network->publishHASSConfig((char*)"Opener", baseTopic.c_str(), (char*)_nukiConfig.name, uidString, (char*)"deactivateRTO", (char*)"activateRTO", (char*)"electricStrikeActuation");
_network->publishHASSConfig((char*)"Opener", baseTopic.c_str(), (char*)_nukiConfig.name, uidString, _publishAuthData, (char*)"deactivateRTO", (char*)"activateRTO", (char*)"electricStrikeActuation");
}
_hassSetupCompleted = true;

View File

@@ -496,12 +496,14 @@ void NukiWrapper::updateAuthData(bool retrieved)
std::list<NukiLock::LogEntry> log;
_nukiLock.getLogEntries(&log);
if(log.size() > _preferences->getInt(preference_authlog_max_entries, 3))
{
log.resize(_preferences->getInt(preference_authlog_max_entries, 3));
}
log.sort([](const NukiLock::LogEntry& a, const NukiLock::LogEntry& b) { return a.index < b.index; });
if(log.size() > 0)
{
_network->publishAuthorizationInfo(log, true);
@@ -517,6 +519,8 @@ void NukiWrapper::updateAuthData(bool retrieved)
{
log.resize(_preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG));
}
log.sort([](const NukiLock::LogEntry& a, const NukiLock::LogEntry& b) { return a.index < b.index; });
Log->print(F("Log size: "));
Log->println(log.size());

View File

@@ -51,6 +51,7 @@
#define preference_access_level (char*)"accLvl"
#define preference_keypad_info_enabled (char*)"kpInfoEnabled"
#define preference_keypad_control_enabled (char*)"kpCntrlEnabled"
#define preference_keypad_publish_code (char*)"kpPubCode"
#define preference_timecontrol_control_enabled (char*)"tcCntrlEnabled"
#define preference_timecontrol_info_enabled (char*)"tcInfoEnabled"
#define preference_publish_authdata (char*)"pubAuth"
@@ -97,7 +98,7 @@ private:
preference_network_hardware, preference_network_wifi_fallback_disabled, preference_rssi_publish_interval, preference_hostname, preference_find_best_rssi,
preference_network_timeout, preference_restart_on_disconnect, preference_restart_ble_beacon_lost, preference_query_interval_lockstate,
preference_query_interval_configuration, preference_query_interval_battery, preference_query_interval_keypad, preference_keypad_control_enabled,
preference_keypad_info_enabled, preference_acl, preference_timecontrol_control_enabled, preference_timecontrol_info_enabled,
preference_keypad_info_enabled, preference_keypad_publish_code, preference_acl, preference_timecontrol_control_enabled, preference_timecontrol_info_enabled,
preference_conf_lock_basic_acl, preference_conf_lock_advanced_acl, preference_conf_opener_basic_acl, preference_conf_opener_advanced_acl,
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_publish_debug_info, preference_presence_detection_timeout, preference_disable_non_json,
@@ -115,8 +116,8 @@ private:
{
preference_started_before, preference_mqtt_log_enabled, preference_check_updates, preference_lock_enabled, preference_opener_enabled, preference_opener_continuous_mode,
preference_enable_bootloop_reset, preference_webserver_enabled, preference_find_best_rssi, preference_restart_on_disconnect, preference_keypad_control_enabled,
preference_keypad_info_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_disable_non_json
preference_keypad_info_enabled, preference_keypad_publish_code, 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_disable_non_json
};
const bool isRedacted(const char* key) const

View File

@@ -561,6 +561,11 @@ bool WebCfgServer::processArgs(String& message)
_preferences->putBool(preference_keypad_info_enabled, (value == "1"));
configChanged = true;
}
else if(key == "KPCODE")
{
_preferences->putBool(preference_keypad_publish_code, (value == "1"));
configChanged = true;
}
else if(key == "KPENA")
{
_preferences->putBool(preference_keypad_control_enabled, (value == "1"));
@@ -1400,12 +1405,13 @@ void WebCfgServer::buildAccLvlHtml(String &response)
if((_nuki != nullptr && _nuki->hasKeypad()) || (_nukiOpener != nullptr && _nukiOpener->hasKeypad()))
{
printCheckBox(response, "KPPUB", "Publish keypad codes information", _preferences->getBool(preference_keypad_info_enabled), "");
printCheckBox(response, "KPPUB", "Publish keypad entries information", _preferences->getBool(preference_keypad_info_enabled), "");
printCheckBox(response, "KPCODE", "Also publish keypad codes (<span style=\"color: #ff0000\">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, "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 authorization log (may reduce battery life)", _preferences->getBool(preference_publish_authdata), "");
response.concat("</table><br>");
if(_nuki != nullptr)
{