diff --git a/MqttTopics.h b/MqttTopics.h index a00474a..a3cfc12 100644 --- a/MqttTopics.h +++ b/MqttTopics.h @@ -9,6 +9,7 @@ #define mqtt_topic_battery_lock_distance "/battery/lockDistance" #define mqtt_topic_lock_state "/lock/state" +#define mqtt_topic_lock_state_json "/lock/stateJson" #define mqtt_topic_lock_binary_state "/lock/binaryState" #define mqtt_topic_lock_trigger "/lock/trigger" #define mqtt_topic_lock_auth_id "/lock/authorizationId" diff --git a/NetworkLock.cpp b/NetworkLock.cpp index 74d5292..83377a7 100644 --- a/NetworkLock.cpp +++ b/NetworkLock.cpp @@ -210,6 +210,47 @@ void NetworkLock::publishKeyTurnerState(const NukiLock::KeyTurnerState& keyTurne _firstTunerStatePublish = false; } +void NetworkLock::publishStateAsJson(const char* action, const NukiLock::KeyTurnerState &keyTurnerState, const uint32_t authId, const char *authName) +{ + char str[50]; + String json = "{\n"; + + // action + json.concat("\"action\": \""); json.concat(action); json.concat("\",\n"); + + // state + memset(&str, 0, sizeof(str)); + lockstateToString(keyTurnerState.lockState, str); + json.concat("\"state\": \""); json.concat(str); json.concat("\",\n"); + + // state + memset(&str, 0, sizeof(str)); + lockstateToString(keyTurnerState.lockState, str); + json.concat("\"state\": \""); json.concat(str); json.concat("\",\n"); + + // trigger + memset(&str, 0, sizeof(str)); + triggerToString(keyTurnerState.trigger, str); + json.concat("\"trigger\": \""); json.concat(str); json.concat("\",\n"); + + // completion status + memset(&str, 0, sizeof(str)); + NukiLock::completionStatusToString(keyTurnerState.lastLockActionCompletionStatus, str); + json.concat("\"completionStatus\": \""); json.concat(str); json.concat("\",\n"); + + // Door sensor state + memset(&str, 0, sizeof(str)); + NukiLock::doorSensorStateToString(keyTurnerState.doorSensorState, str); + json.concat("\"doorSensorState\": \""); json.concat(str); json.concat("\",\n"); + + // Auth date + json.concat("\"authorizationId\": "); json.concat(authId == 0xffff ? 0 : authId); json.concat(",\n"); + json.concat("\"authorizationName\": \""); json.concat(authName); json.concat("\"\n"); + + json.concat("}"); + publishString(mqtt_topic_lock_state_json, json.c_str()); +} + void NetworkLock::publishBinaryState(NukiLock::LockState lockState) { switch(lockState) diff --git a/NetworkLock.h b/NetworkLock.h index 0457bc0..05beb57 100644 --- a/NetworkLock.h +++ b/NetworkLock.h @@ -21,6 +21,7 @@ public: void update(); void publishKeyTurnerState(const NukiLock::KeyTurnerState& keyTurnerState, const NukiLock::KeyTurnerState& lastKeyTurnerState); + void publishStateAsJson(const char* action, const NukiLock::KeyTurnerState& keyTurnerState, const uint32_t authId, const char* authName); void publishBinaryState(NukiLock::LockState lockState); void publishAuthorizationInfo(const uint32_t authId, const char* authName); void publishCommandResult(const char* resultStr); diff --git a/NukiWrapper.cpp b/NukiWrapper.cpp index 8618958..621107c 100644 --- a/NukiWrapper.cpp +++ b/NukiWrapper.cpp @@ -44,6 +44,7 @@ void NukiWrapper::initialize() _intervalKeypad = _preferences->getInt(preference_query_interval_keypad); _keypadEnabled = _preferences->getBool(preference_keypad_control_enabled); _publishAuthData = _preferences->getBool(preference_publish_authdata); + _publishJson = _preferences->getBool(preference_publish_json); _maxKeypadCodeCount = _preferences->getUInt(preference_max_keypad_code_count); if(_intervalLockstate == 0) @@ -122,21 +123,21 @@ void NukiWrapper::update() if(_nextLockAction != (NukiLock::LockAction)0xff) { - Nuki::CmdResult cmdResult = _nukiLock.lockAction(_nextLockAction, 0, 0); + Nuki::CmdResult cmdResult = _nukiLock.lockAction(_nextLockAction, 0, 0); - char resultStr[15] = {0}; - NukiLock::cmdResultToString(cmdResult, resultStr); + char resultStr[15] = {0}; + NukiLock::cmdResultToString(cmdResult, resultStr); - _network->publishCommandResult(resultStr); + _network->publishCommandResult(resultStr); - Serial.print(F("Lock action result: ")); - Serial.println(resultStr); + Serial.print(F("Lock action result: ")); + Serial.println(resultStr); - _nextLockAction = (NukiLock::LockAction)0xff; - if(_intervalLockstate > 10) - { - _nextLockStateUpdateTs = ts + 10 * 1000; - } + _nextLockAction = (NukiLock::LockAction)0xff; + if(_intervalLockstate > 10) + { + _nextLockStateUpdateTs = ts + 10 * 1000; + } } if(_clearAuthData) @@ -191,6 +192,11 @@ void NukiWrapper::updateKeyTurnerState() { updateAuthData(); } + + if(_publishJson) + { + _network->publishStateAsJson(_lastLockAction, _keyTurnerState, _lastAuthId, _lastAuthName); + } } void NukiWrapper::updateBatteryState() @@ -233,17 +239,20 @@ void NukiWrapper::updateAuthData() if(log.size() > 0) { const Nuki::LogEntry& entry = log.front(); -// log_d("Log: %d-%d-%d %d:%d:%d %s", entry.timeStampYear, entry.timeStampMonth, entry.timeStampDay, -// entry.timeStampHour, entry.timeStampMinute, entry.timeStampSecond, entry.name); + if(entry.authId != _lastAuthId) { _network->publishAuthorizationInfo(entry.authId, (char *) entry.name); _lastAuthId = entry.authId; + memset(_lastAuthName, 0, sizeof(_lastAuthName)); + memcpy(_lastAuthName, entry.name, sizeof(entry.name)); } } else { _network->publishAuthorizationInfo(0, ""); + _lastAuthId = 0; + memset(_lastAuthName, 0, sizeof(_lastAuthName)); } } @@ -277,6 +286,9 @@ void NukiWrapper::updateKeypad() NukiLock::LockAction NukiWrapper::lockActionToEnum(const char *str) { + memset(&_lastLockAction, 0, sizeof(_lastLockAction)); + strcpy(_lastLockAction, str); + if(strcmp(str, "unlock") == 0) return NukiLock::LockAction::Unlock; else if(strcmp(str, "lock") == 0) return NukiLock::LockAction::Lock; else if(strcmp(str, "unlatch") == 0) return NukiLock::LockAction::Unlatch; diff --git a/NukiWrapper.h b/NukiWrapper.h index f27e28e..c6fd654 100644 --- a/NukiWrapper.h +++ b/NukiWrapper.h @@ -67,6 +67,7 @@ private: NukiLock::KeyTurnerState _keyTurnerState; uint32_t _lastAuthId = 0xffff; + char _lastAuthName[33] = {0}; NukiLock::BatteryReport _batteryReport; NukiLock::BatteryReport _lastBatteryReport; @@ -81,10 +82,12 @@ private: bool _hasKeypad = false; bool _keypadEnabled = false; bool _configRead = false; + bool _publishJson = false; uint _maxKeypadCodeCount = 0; unsigned long _nextLockStateUpdateTs = 0; unsigned long _nextBatteryReportTs = 0; unsigned long _nextConfigUpdateTs = 0; unsigned long _nextKeypadUpdateTs = 0; NukiLock::LockAction _nextLockAction = (NukiLock::LockAction)0xff; + char _lastLockAction[15] = { 0 }; }; diff --git a/PreferencesKeys.h b/PreferencesKeys.h index 1f00e7c..69dca45 100644 --- a/PreferencesKeys.h +++ b/PreferencesKeys.h @@ -23,6 +23,7 @@ #define preference_query_interval_battery "batInterval" #define preference_query_interval_keypad "kpInterval" #define preference_keypad_control_enabled "kpEnabled" +#define preference_publish_json "pubJson" #define preference_cred_user "crdusr" #define preference_cred_password "crdpass" #define preference_publish_authdata "pubauth" diff --git a/WebCfgServer.cpp b/WebCfgServer.cpp index a871eb8..3264444 100644 --- a/WebCfgServer.cpp +++ b/WebCfgServer.cpp @@ -296,6 +296,11 @@ bool WebCfgServer::processArgs(String& message) _preferences->putBool(preference_keypad_control_enabled, (value == "1")); configChanged = true; } + else if(key == "PUBJSON") + { + _preferences->putBool(preference_publish_json, (value == "1")); + configChanged = true; + } else if(key == "PRDTMO") { _preferences->putInt(preference_presence_detection_timeout, value.toInt()); @@ -557,7 +562,7 @@ void WebCfgServer::buildMqttConfigHtml(String &response) { buildHtmlHeader(response); response.concat("