diff --git a/README.md b/README.md index 2dba8a9..41c58e9 100644 --- a/README.md +++ b/README.md @@ -192,9 +192,10 @@ In a browser navigate to the IP address assigned to the ESP32. ### Lock - lock/action: Allows to execute lock actions. After receiving the action, the value is set to "ack". Possible actions: unlock, lock, unlatch, lockNgo, lockNgoUnlatch, fullLock, fobAction1, fobAction2, fobAction3. +- lock/statusUpdated: 1 when the Nuki Lock/Opener signals the KeyTurner state has been updated, resets to 0 when Nuki Hub has queried the updated state. - lock/state: Reports the current lock state as a string. Possible values are: uncalibrated, locked, unlocked, unlatched, unlockedLnga, unlatching, bootRun, motorBlocked. - lock/hastate: Reports the current lock state as a string, specifically for use by Home Assistant. Possible values are: locking, locked, unlocking, unlocked, jammed. -- lock/json: Reports the lock state, last action trigger, last lock action, lock completion status, door sensor state, auth ID and auth name as JSON data. +- lock/json: Reports the lock state, lockngo_state, trigger, current time, time zone offset, night mode state, last action trigger, last lock action, lock completion status, door sensor state, auth ID and auth name as JSON data. - lock/binaryState: Reports the current lock state as a string, mostly for use by Home Assistant. Possible values are: locked, unlocked. - 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. @@ -206,14 +207,14 @@ In a browser navigate to the IP address assigned to the ESP32. - lock/doorSensorState: State of the door sensor: unavailable, deactivated, doorClosed, doorOpened, doorStateUnknown, calibrating. - lock/rssi: The signal strenght of the Nuki Lock as measured by the ESP32 and expressed by the RSSI Value in dBm. - lock/address: The BLE address of the Nuki Lock. -- lock/retry: Reports the current number of retries for the current command. 0 when command is succesfull, "failed" if the number of retries is greater than the maximum configured number of retries. +- lock/retry: Reports the current number of retries for the current command. 0 when command is successful, "failed" if the number of retries is greater than the maximum configured number of retries. ### Opener - lock/action: Allows to execute lock actions. After receiving the action, the value is set to "ack". Possible actions: activateRTO, deactivateRTO, electricStrikeActuation, activateCM, deactivateCM, fobAction1, fobAction2, fobAction3. - lock/state: Reports the current lock state as a string. Possible values are: locked, RTOactive, open, opening, uncalibrated. - lock/hastate: Reports the current lock state as a string, specifically for use by Home Assistant. Possible values are: locking, locked, unlocking, unlocked, jammed. -- lock/json: Reports the lock state, last action trigger, last lock action, lock completion status, door sensor state, auth ID and auth name as JSON data. +- lock/json: Reports the lock state, trigger, ring to open timer, current time, time zone offset, last action trigger, last lock action, lock completion status, door sensor state, auth ID and auth name as JSON data. - lock/binaryState: Reports the current lock state as a string, mostly for use by Home Assistant. Possible values are: locked, unlocked. - lock/continuousMode: Enable or disable continuous mode on the opener (0 = disabled; 1 = enabled). - lock/ring: The string "ring" is published to this topic when a doorbell ring is detected while RTO or continuous mode is active or "ringlocked" when both are inactive. @@ -228,7 +229,7 @@ In a browser navigate to the IP address assigned to the ESP32. - lock/doorSensorState: State of the door sensor: unavailable, deactivated, doorClosed, doorOpened, doorStateUnknown, calibrating. - lock/rssi: The bluetooth signal strength of the Nuki Lock as measured by the ESP32 and expressed by the RSSI Value in dBm. - lock/address: The BLE address of the Nuki Lock. -- lock/retry: Reports the current number of retries for the current command. 0 when command is succesfull, "failed" if the number of retries is greater than the maximum configured number of retries. +- lock/retry: Reports the current number of retries for the current command. 0 when command is successful, "failed" if the number of retries is greater than the maximum configured number of retries. ### Configuration - configuration/buttonEnabled: 1 if the Nuki Lock/Opener button is enabled, otherwise 0. diff --git a/src/MqttTopics.h b/src/MqttTopics.h index 6178a6c..f52dbbd 100644 --- a/src/MqttTopics.h +++ b/src/MqttTopics.h @@ -1,6 +1,7 @@ #pragma once #define mqtt_topic_lock_action "/lock/action" +#define mqtt_topic_lock_status_updated "/lock/statusUpdated" #define mqtt_topic_lock_state "/lock/state" #define mqtt_topic_lock_ha_state "/lock/hastate" #define mqtt_topic_lock_json "/lock/json" diff --git a/src/NetworkLock.cpp b/src/NetworkLock.cpp index d865427..2762bbe 100644 --- a/src/NetworkLock.cpp +++ b/src/NetworkLock.cpp @@ -241,7 +241,7 @@ void NetworkLock::publishKeyTurnerState(const NukiLock::KeyTurnerState& keyTurne lockstateToString(keyTurnerState.lockState, str); - if((_firstTunerStatePublish || keyTurnerState.lockState != lastKeyTurnerState.lockState) && keyTurnerState.lockState != NukiLock::LockState::Undefined) + if(keyTurnerState.lockState != NukiLock::LockState::Undefined) { publishString(mqtt_topic_lock_state, str); @@ -253,6 +253,7 @@ void NetworkLock::publishKeyTurnerState(const NukiLock::KeyTurnerState& keyTurne } json["lock_state"] = str; + json["lockngo_state"] = (keyTurnerState.lockNgoTimer == 0 ? 0 : 1); memset(&str, 0, sizeof(str)); triggerToString(keyTurnerState.trigger, str); @@ -263,6 +264,12 @@ void NetworkLock::publishKeyTurnerState(const NukiLock::KeyTurnerState& keyTurne } json["trigger"] = str; + + char curTime[20]; + sprintf(curTime, "%04d-%02d-%02d %02d:%02d:%02d", keyTurnerState.currentTimeYear, keyTurnerState.currentTimeMonth, keyTurnerState.currentTimeDay, keyTurnerState.currentTimeHour, keyTurnerState.currentTimeMinute, keyTurnerState.currentTimeSecond); + json["currentTime"] = curTime; + json["timeZoneOffset"] = keyTurnerState.timeZoneOffset; + json["nightModeActive"] = keyTurnerState.nightModeActive; memset(&str, 0, sizeof(str)); lockactionToString(keyTurnerState.lastLockAction, str); @@ -274,6 +281,10 @@ void NetworkLock::publishKeyTurnerState(const NukiLock::KeyTurnerState& keyTurne json["last_lock_action"] = str; + memset(&str, 0, sizeof(str)); + triggerToString(keyTurnerState.lastLockActionTrigger, str); + json["last_lock_action_trigger"] = str; + memset(&str, 0, sizeof(str)); NukiLock::completionStatusToString(keyTurnerState.lastLockActionCompletionStatus, str); @@ -806,6 +817,11 @@ void NetworkLock::publishTimeControlCommandResult(const char* result) publishString(mqtt_topic_timecontrol_command_result, result); } +void NetworkLock::publishStatusUpdated(const bool statusUpdated) +{ + publishBool(mqtt_topic_lock_status_updated, statusUpdated); +} + void NetworkLock::setLockActionReceivedCallback(LockActionResult (*lockActionReceivedCallback)(const char *)) { _lockActionReceivedCallback = lockActionReceivedCallback; diff --git a/src/NetworkLock.h b/src/NetworkLock.h index 5414ea4..e6c3104 100644 --- a/src/NetworkLock.h +++ b/src/NetworkLock.h @@ -38,6 +38,7 @@ public: void removeHASSConfig(char* uidString); void publishKeypad(const std::list& entries, uint maxKeypadCodeCount); void publishTimeControl(const std::list& timeControlEntries); + void publishStatusUpdated(const bool statusUpdated); void publishConfigCommandResult(const char* result); void publishKeypadCommandResult(const char* result); void publishKeypadJsonCommandResult(const char* result); diff --git a/src/NetworkOpener.cpp b/src/NetworkOpener.cpp index d7cf278..b149a6b 100644 --- a/src/NetworkOpener.cpp +++ b/src/NetworkOpener.cpp @@ -265,6 +265,25 @@ void NetworkOpener::publishKeyTurnerState(const NukiOpener::OpenerState& keyTurn } json["trigger"] = str; + + json["ringToOpenTimer"] = keyTurnerState.ringToOpenTimer; + char curTime[20]; + sprintf(curTime, "%04d-%02d-%02d %02d:%02d:%02d", keyTurnerState.currentTimeYear, keyTurnerState.currentTimeMonth, keyTurnerState.currentTimeDay, keyTurnerState.currentTimeHour, keyTurnerState.currentTimeMinute, keyTurnerState.currentTimeSecond); + json["currentTime"] = curTime; + json["timeZoneOffset"] = keyTurnerState.timeZoneOffset; + + lockactionToString(keyTurnerState.lastLockAction, str); + + if(_firstTunerStatePublish || keyTurnerState.lastLockAction != lastKeyTurnerState.lastLockAction) + { + publishString(mqtt_topic_lock_last_lock_action, str); + } + + json["last_lock_action"] = str; + + memset(&str, 0, sizeof(str)); + triggerToString(keyTurnerState.lastLockActionTrigger, str); + json["last_lock_action_trigger"] = str; memset(&str, 0, sizeof(str)); completionStatusToString(keyTurnerState.lastLockActionCompletionStatus, str); @@ -864,6 +883,11 @@ void NetworkOpener::publishTimeControlCommandResult(const char* result) { publishString(mqtt_topic_timecontrol_command_result, result); } + +void NetworkOpener::publishStatusUpdated(const bool statusUpdated) +{ + publishBool(mqtt_topic_lock_status_updated, statusUpdated); +} void NetworkOpener::setLockActionReceivedCallback(LockActionResult (*lockActionReceivedCallback)(const char *)) { diff --git a/src/NetworkOpener.h b/src/NetworkOpener.h index de1f739..d814933 100644 --- a/src/NetworkOpener.h +++ b/src/NetworkOpener.h @@ -35,6 +35,7 @@ public: void removeHASSConfig(char* uidString); void publishKeypad(const std::list& entries, uint maxKeypadCodeCount); void publishTimeControl(const std::list& timeControlEntries); + void publishStatusUpdated(const bool statusUpdated); void publishConfigCommandResult(const char* result); void publishKeypadCommandResult(const char* result); void publishKeypadJsonCommandResult(const char* result); diff --git a/src/NukiOpenerWrapper.cpp b/src/NukiOpenerWrapper.cpp index a8bba92..30fb5de 100644 --- a/src/NukiOpenerWrapper.cpp +++ b/src/NukiOpenerWrapper.cpp @@ -154,9 +154,10 @@ void NukiOpenerWrapper::update() if(_statusUpdated || _nextLockStateUpdateTs == 0 || ts >= _nextLockStateUpdateTs || (queryCommands & QUERY_COMMAND_LOCKSTATE) > 0) { + _statusUpdated = false; _nextLockStateUpdateTs = ts + _intervalLockstate * 1000; updateKeyTurnerState(); - _statusUpdated = false; + _network->publishStatusUpdated(_statusUpdated); } if(_nextBatteryReportTs == 0 || ts > _nextBatteryReportTs || (queryCommands & QUERY_COMMAND_BATTERY) > 0) { @@ -1964,6 +1965,7 @@ void NukiOpenerWrapper::notify(Nuki::EventType eventType) if(eventType == Nuki::EventType::KeyTurnerStatusUpdated) { _statusUpdated = true; + _network->publishStatusUpdated(_statusUpdated); } } diff --git a/src/NukiWrapper.cpp b/src/NukiWrapper.cpp index 46c7564..4ef0f9e 100644 --- a/src/NukiWrapper.cpp +++ b/src/NukiWrapper.cpp @@ -176,6 +176,7 @@ void NukiWrapper::update() _statusUpdated = false; _nextLockStateUpdateTs = ts + _intervalLockstate * 1000; updateKeyTurnerState(); + _network->publishStatusUpdated(_statusUpdated); } if(_nextBatteryReportTs == 0 || ts > _nextBatteryReportTs || (queryCommands & QUERY_COMMAND_BATTERY) > 0) { @@ -1940,6 +1941,7 @@ void NukiWrapper::notify(Nuki::EventType eventType) if(eventType == Nuki::EventType::KeyTurnerStatusUpdated) { _statusUpdated = true; + _network->publishStatusUpdated(_statusUpdated); } }