From 507bbb570e01166484c53f66cb0f0ecbe79cb812 Mon Sep 17 00:00:00 2001 From: iranl Date: Thu, 16 May 2024 19:55:22 +0200 Subject: [PATCH] Extend keyturner state and publish Nuki device status updated --- README.md | 9 +++++---- src/MqttTopics.h | 1 + src/NetworkLock.cpp | 18 +++++++++++++++++- src/NetworkLock.h | 1 + src/NetworkOpener.cpp | 24 ++++++++++++++++++++++++ src/NetworkOpener.h | 1 + src/NukiOpenerWrapper.cpp | 4 +++- src/NukiWrapper.cpp | 2 ++ 8 files changed, 54 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index edd44e0..0e441b0 100644 --- a/README.md +++ b/README.md @@ -191,9 +191,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. @@ -205,14 +206,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. @@ -227,7 +228,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 8e6a160..95e7397 100644 --- a/src/NetworkLock.cpp +++ b/src/NetworkLock.cpp @@ -242,7 +242,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); @@ -254,6 +254,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); @@ -264,6 +265,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); @@ -275,6 +282,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); @@ -809,6 +820,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 c1f791e..1c9277e 100644 --- a/src/NetworkOpener.cpp +++ b/src/NetworkOpener.cpp @@ -266,6 +266,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); @@ -867,6 +886,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 a7e0b31..72d52ba 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 daee4b4..4036cb8 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) { @@ -1962,6 +1963,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 1b28b3e..119cb15 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) { @@ -1938,6 +1939,7 @@ void NukiWrapper::notify(Nuki::EventType eventType) if(eventType == Nuki::EventType::KeyTurnerStatusUpdated) { _statusUpdated = true; + _network->publishStatusUpdated(_statusUpdated); } }