From 51eb268f53efdf216ce32bba5d214c770dffff45 Mon Sep 17 00:00:00 2001 From: iranl Date: Fri, 4 Apr 2025 15:47:24 +0200 Subject: [PATCH 1/4] New commands --- src/NukiBle.cpp | 65 ++++++- src/NukiBle.h | 31 +++- src/NukiConstants.h | 278 ++++++++++++++++++++++------ src/NukiLock.cpp | 153 ++++++++++++++++ src/NukiLock.h | 51 +++++- src/NukiLockConstants.h | 13 ++ src/NukiLockUtils.cpp | 396 +++++++++++++++++++++++++++++----------- src/NukiLockUtils.h | 12 ++ src/NukiOpenerUtils.cpp | 24 +-- 9 files changed, 846 insertions(+), 177 deletions(-) diff --git a/src/NukiBle.cpp b/src/NukiBle.cpp index 73b758a7..c3d78f9b 100644 --- a/src/NukiBle.cpp +++ b/src/NukiBle.cpp @@ -786,6 +786,38 @@ Nuki::CmdResult NukiBle::addKeypadEntry(NewKeypadEntry newKeypadEntry) { return result; } +Nuki::CmdResult NukiBle::genericCommand(Command command, bool withPin) { + NukiLock::Action action; + + if (withPin) { + action.cmdType = Nuki::CommandType::CommandWithChallengeAndPin; + } else { + action.cmdType = Nuki::CommandType::CommandWithChallenge; + } + action.command = command; + + Nuki::CmdResult result = executeAction(action); + return result; +} + +Nuki::CmdResult NukiBle::requestDailyStatistics() { + NukiLock::Action action; + unsigned char payload[5] = {0}; + payload[0] = 0; + payload[1] = 0; + payload[2] = 0; + payload[3] = 0; + payload[4] = 5; + + action.cmdType = Nuki::CommandType::CommandWithChallengeAndPin; + action.command = Nuki::Command::RequestDailyStatistics; + memcpy(action.payload, &payload, sizeof(payload)); + action.payloadLen = sizeof(payload); + + Nuki::CmdResult result = executeAction(action); + return result; +} + Nuki::CmdResult NukiBle::updateKeypadEntry(UpdatedKeypadEntry updatedKeyPadEntry) { //TODO verify data validity NukiLock::Action action; @@ -806,6 +838,15 @@ Nuki::CmdResult NukiBle::updateKeypadEntry(UpdatedKeypadEntry updatedKeyPadEntry return result; } +void NukiBle::getFingerprintEntries(std::list* requestedFingerprintEntries) { + requestedFingerprintEntries->clear(); + std::list::iterator it = listOfFingerprintEntries.begin(); + while (it != listOfFingerprintEntries.end()) { + requestedFingerprintEntries->push_back(*it); + it++; + } +} + void NukiBle::getKeypadEntries(std::list* requestedKeypadCodes) { requestedKeypadCodes->clear(); std::list::iterator it = listOfKeyPadEntries.begin(); @@ -832,6 +873,17 @@ CmdResult NukiBle::deleteKeypadEntry(uint16_t id) { return executeAction(action); } +Nuki::CmdResult NukiBle::retrieveFingerprintEntries() { + NukiLock::Action action; + + action.cmdType = Nuki::CommandType::CommandWithChallengeAndPin; + action.command = Command::RequestFingerprintEntries; + + listOfFingerprintEntries.clear(); + + return executeAction(action); +} + Nuki::CmdResult NukiBle::retrieveAuthorizationEntries(const uint16_t offset, const uint16_t count) { NukiLock::Action action; unsigned char payload[4] = {0}; @@ -1745,7 +1797,6 @@ void NukiBle::handleReturnMessage(Command returnCode, unsigned char* data, uint1 } break; } - case Command::Status : { printBuffer((byte*)data, dataLen, false, "status", debugNukiHexData, logger); receivedStatus = data[0]; @@ -1763,7 +1814,6 @@ void NukiBle::handleReturnMessage(Command returnCode, unsigned char* data, uint1 logMessage("NOT IMPLEMENTED ONLY FOR NUKI v1", 2); //command is not available on Nuki v2 (only on Nuki v1) break; } - case Command::ErrorReport : { if (logger == nullptr) { log_e("Error: %02x for command: %02x:%02x", data[0], data[2], data[1]); @@ -1836,6 +1886,17 @@ void NukiBle::handleReturnMessage(Command returnCode, unsigned char* data, uint1 break; } + case Command::FingerprintEntry : { + FingerprintEntry fingerprintEntry; + memcpy(&fingerprintEntry, data, dataLen); + listOfFingerprintEntries.push_back(fingerprintEntry); + + printBuffer((byte*)data, dataLen, false, "fingerprintEntry", debugNukiHexData, logger); + if (debugNukiReadableData) { + NukiLock::logFingerprintEntry(fingerprintEntry, true, logger); + } + break; + } case Command::KeypadCode : { KeypadEntry keypadEntry; memcpy(&keypadEntry, data, dataLen); diff --git a/src/NukiBle.h b/src/NukiBle.h index 8ca126e3..63f108ad 100644 --- a/src/NukiBle.h +++ b/src/NukiBle.h @@ -179,13 +179,26 @@ class NukiBle : public BLEClientCallbacks, public BleScanner::Subscriber { */ void getKeypadEntries(std::list* requestedKeyPadEntries); + /** + * @brief Request the lock via BLE to send the existing fingerprint entries + * + */ + Nuki::CmdResult retrieveFingerprintEntries(); + + /** + * @brief Get the Fingerprint Entries stored on the esp (after executing retrieveFingerprintEntries) + * + * @param requestedFingerprintEntries list to store the returned Fingerprint entries + */ + void getFingerprintEntries(std::list* requestedFingerprintEntries); + /** * @brief Delete a Keypad Entry * * @param id Id to be deleted */ CmdResult deleteKeypadEntry(uint16_t id); - + /** * @brief Request the lock via BLE to send the existing authorizationentries * @@ -232,6 +245,20 @@ class NukiBle : public BLEClientCallbacks, public BleScanner::Subscriber { * */ Nuki::CmdResult requestReboot(); + + /** + * @brief Sends a custom command to the lock via BLE + * + * @param command Nuki command to execute + * @param withPin Set to true when using challenge and pin command + */ + Nuki::CmdResult genericCommand(Command command, bool withPin = true); + + /** + * @brief Sends a request for daily statistics to the lock via BLE + * + */ + Nuki::CmdResult requestDailyStatistics(); /** * @brief Sends the time to be set to the lock via BLE @@ -548,9 +575,9 @@ class NukiBle : public BLEClientCallbacks, public BleScanner::Subscriber { #endif std::list listOfKeyPadEntries; + std::list listOfFingerprintEntries; std::list listOfAuthorizationEntries; AuthorizationIdType authorizationIdType = AuthorizationIdType::Bridge; - }; } // namespace Nuki diff --git a/src/NukiConstants.h b/src/NukiConstants.h index a5e7738c..d0329b1f 100644 --- a/src/NukiConstants.h +++ b/src/NukiConstants.h @@ -65,62 +65,97 @@ enum class CommandStatus : uint8_t { }; enum class Command : uint16_t { - Empty = 0x0000, - RequestData = 0x0001, - PublicKey = 0x0003, - Challenge = 0x0004, - AuthorizationAuthenticator = 0x0005, - AuthorizationData = 0x0006, - AuthorizationId = 0x0007, - RemoveUserAuthorization = 0x0008, - RequestAuthorizationEntries = 0x0009, - AuthorizationEntry = 0x000A, - AuthorizationDatInvite = 0x000B, - KeyturnerStates = 0x000C, - LockAction = 0x000D, - Status = 0x000E, - MostRecentCommand = 0x000F, - OpeningsClosingsSummary = 0x0010, // Lock only (+ NUKI v1 only) - BatteryReport = 0x0011, - ErrorReport = 0x0012, - SetConfig = 0x0013, - RequestConfig = 0x0014, - Config = 0x0015, - SetSecurityPin = 0x0019, - RequestCalibration = 0x001A, // SetCalibrated for Opener - RequestReboot = 0x001D, - AuthorizationIdConfirmation = 0x001E, - AuthorizationIdInvite = 0x001F, - VerifySecurityPin = 0x0020, - UpdateTime = 0x0021, - UpdateAuthorization = 0x0025, - AuthorizationEntryCount = 0x0027, - StartBusSignalRecording = 0x002F, // Opener only - RequestLogEntries = 0x0031, - LogEntry = 0x0032, - LogEntryCount = 0x0033, - EnableLogging = 0x0034, - SetAdvancedConfig = 0x0035, - RequestAdvancedConfig = 0x0036, - AdvancedConfig = 0x0037, - AddTimeControlEntry = 0x0039, - TimeControlEntryId = 0x003A, - RemoveTimeControlEntry = 0x003B, - RequestTimeControlEntries = 0x003C, - TimeControlEntryCount = 0x003D, - TimeControlEntry = 0x003E, - UpdateTimeControlEntry = 0x003F, - AddKeypadCode = 0x0041, - KeypadCodeId = 0x0042, - RequestKeypadCodes = 0x0043, - KeypadCodeCount = 0x0044, - KeypadCode = 0x0045, - UpdateKeypadCode = 0x0046, - RemoveKeypadCode = 0x0047, - KeypadAction = 0x0048, - AuthorizationInfo = 0x004C, - ContinuousModeAction = 0x0057, // Opener only - SimpleLockAction = 0x0100 + Empty = 0x0000, + RequestData = 0x0001, + PublicKey = 0x0003, + Challenge = 0x0004, + AuthorizationAuthenticator = 0x0005, + AuthorizationData = 0x0006, + AuthorizationId = 0x0007, + RemoveUserAuthorization = 0x0008, + RequestAuthorizationEntries = 0x0009, + AuthorizationEntry = 0x000A, + AuthorizationDatInvite = 0x000B, + KeyturnerStates = 0x000C, + LockAction = 0x000D, + Status = 0x000E, + MostRecentCommand = 0x000F, + OpeningsClosingsSummary = 0x0010, // Lock only (+ NUKI v1 only) + BatteryReport = 0x0011, + ErrorReport = 0x0012, + SetConfig = 0x0013, + RequestConfig = 0x0014, + Config = 0x0015, + SetSecurityPin = 0x0019, + RequestCalibration = 0x001A, // SetCalibrated for Opener + RequestReboot = 0x001D, + AuthorizationIdConfirmation = 0x001E, + AuthorizationIdInvite = 0x001F, + VerifySecurityPin = 0x0020, + UpdateTime = 0x0021, + UpdateAuthorization = 0x0025, + AuthorizationEntryCount = 0x0027, + StartBusSignalRecording = 0x002F, // Opener only + RequestLogEntries = 0x0031, + LogEntry = 0x0032, + LogEntryCount = 0x0033, + EnableLogging = 0x0034, + SetAdvancedConfig = 0x0035, + RequestAdvancedConfig = 0x0036, + AdvancedConfig = 0x0037, + AddTimeControlEntry = 0x0039, + TimeControlEntryId = 0x003A, + RemoveTimeControlEntry = 0x003B, + RequestTimeControlEntries = 0x003C, + TimeControlEntryCount = 0x003D, + TimeControlEntry = 0x003E, + UpdateTimeControlEntry = 0x003F, + AddKeypadCode = 0x0041, + KeypadCodeId = 0x0042, + RequestKeypadCodes = 0x0043, + KeypadCodeCount = 0x0044, + KeypadCode = 0x0045, + UpdateKeypadCode = 0x0046, + RemoveKeypadCode = 0x0047, + KeypadAction = 0x0048, + RestoreConfig = 0x004B, + AuthorizationInfo = 0x004C, + ContinuousModeAction = 0x0057, // Opener only + RequestDoorSensorConfig = 0x0058, + DoorSensorConfig = 0x0059, + RequestDailyStatistics = 0x0060, + DailyStatistics = 0x0061, + RequestGeneralStatistics = 0x0063, + GeneralStatistics = 0x0064, + RequestInternalLogEntries = 0x0065, + InternalLogEntry = 0x0066, + CheckKeypadCode = 0x006E, + ScanWifi = 0x0080, + WifiScanEntry = 0x0081, + ConnectWifi = 0x0082, + ReadWifiConfig = 0x0085, + WifiConfig = 0x0086, + SetWifiConfig = 0x0087, + ReadWifiConfigForMigration = 0x0089, + WifiConfigForMigration = 0x008A, + RequestMqttConfig = 0x008B, + MqttConfig = 0x008C, + SetMqttConfig = 0x008D, + RequestMqttConfigForMigration = 0x008E, + MqttConfigForMigration = 0x008F, + AccessoryInfo = 0x0090, + RequestAccessoryInfo = 0x0091, + RequestFingerprintEntries = 0x0098, + FingerprintEntry = 0x0099, + GetKeypad2Config = 0x009A, + Keypad2Config = 0x009B, + SetKeypad2Config = 0x009C, + SimpleLockAction = 0x0100, + EnableMatterCommissioning = 0x0110, + SetMatterState = 0x0111, + RequestMatterPairings = 0x0112, + MatterPairing = 0x0113, + MatterPairingCount = 0x0114 }; enum class AuthorizationIdType : uint8_t { @@ -247,6 +282,137 @@ struct __attribute__((packed)) KeypadEntry { uint8_t allowedUntilTimeMin; }; +struct __attribute__((packed)) FingerprintEntry { + uint8_t fingerprintId[32]; + uint16_t keypadCodeId = 0; + uint8_t name[20]; +}; + +struct __attribute__((packed)) DailyStatistics { + uint16_t dateYear = 0; + uint8_t dateMonth = 0; + uint8_t dateDay = 0; + //uint8_t dateHour = 0; + //uint8_t dateMinute = 0; + //uint8_t dateSecond = 0; + uint8_t version = 0; + uint16_t countSuccessfulLockActions = 0; + uint16_t countErroneousLockActions = 0; + uint16_t avgCurrentConsumptionLock = 0; + uint16_t maxCurrentConsumptionLock = 0; + uint16_t batteryMinStartVoltageLock = 0; + uint16_t countSuccessfulUnlatchActions = 0; + uint16_t countErroneousUnlatchActions = 0; + uint16_t avgCurrentConsumptionUnlatch = 0; + uint16_t maxCurrentConsumptionUnlatch = 0; + uint16_t batteryMinStartVoltageUnlatch = 0; + uint16_t incomingCommands = 0; + uint16_t outgoingCommands = 0; + uint8_t maxTemperature = 0; + uint8_t minTemperature = 0; + uint8_t avgTemperature = 0; + uint16_t numDoorSensorStatusChanges = 0; + uint8_t maxBatteryPercentage = 0; + uint8_t minBatteryPercentage = 0; + uint32_t idleTime = 0; + uint32_t connectionTime = 0; + uint32_t actionTime = 0; +}; + +struct __attribute__((packed)) GeneralStatistics { + uint8_t version = 0; + uint16_t firstCalibrationYear = 0; + uint8_t firstCalibrationMonth = 0; + uint8_t firstCalibrationDay = 0; + uint16_t calibrationCount = 0; + uint16_t lockActionCount = 0; + uint16_t unlatchCount = 0; + uint16_t lastRebootDateYear = 0; + uint8_t lastRebootDateMonth = 0; + uint8_t lastRebootDateDay = 0; + uint8_t lastRebootDateHour = 0; + uint8_t lastRebootDateMinute = 0; + uint8_t lastRebootDateSecond = 0; + uint16_t lastChargeDateYear = 0; + uint8_t lastChargeDateMonth = 0; + uint8_t lastChargeDateDay = 0; + uint8_t lastChargeDateHour = 0; + uint8_t lastChargeDateMinute = 0; + uint8_t lastChargeDateSecond = 0; + uint16_t initialBatteryVoltage = 0; + uint16_t numActionsDuringBatteryCycle = 0; + uint16_t numUnexpectedReboots = 0; +}; + +struct __attribute__((packed)) MqttConfig { + uint8_t enabled = 0; + uint8_t hostName[32]; + uint8_t userName[32]; + uint8_t secureConnection = 0; + uint8_t autoDiscovery = 0; + uint8_t lockingEnabled = 0; +}; + +struct __attribute__((packed)) MqttConfigForMigration { + uint8_t enabled = 0; + uint8_t hostName[32]; + uint8_t userName[32]; + uint8_t secureConnection = 0; + uint8_t autoDiscovery = 0; + uint8_t lockingEnabled = 0; + uint8_t passphrase[32]; +}; + +struct __attribute__((packed)) AccessoryInfo { + uint16_t dateYear = 0; + uint8_t dateMonth = 0; + uint8_t dateDay = 0; + uint8_t dateHour = 0; + uint8_t dateMinute = 0; + uint8_t dateSecond = 0; + uint32_t accessoryNukiId = 0; + uint8_t accessoryType = 0; + unsigned char firmwareVersion[3] = {0, 0 , 0}; + unsigned char hardwareRevision[2] = {0, 0}; + uint8_t productVariantDifferentiator = 0; + uint16_t mostRecentBatteryVoltage = 0; + uint8_t mostRecentTemperature = 0; + //mostRecentEventData +}; + +struct __attribute__((packed)) WifiScanEntry { + uint8_t ssid[32]; + uint8_t type = 0; + uint8_t signal = 0; +}; + +struct __attribute__((packed)) WifiConfig { + uint32_t serverBridgeId = 0; + uint8_t wifiEnabled = 0; + uint16_t wifiExpertSettings = 0; +}; + +struct __attribute__((packed)) WifiConfigForMigration { + uint8_t ssid[32]; + uint8_t type = 0; + uint8_t passphrase[32]; +}; + +struct __attribute__((packed)) Keypad2Config { + uint8_t updatePending = 0; + uint8_t ledBrightness = 0; + uint8_t batteryType = 0; + uint8_t buttonMode = 0; + uint8_t lockAction = 0; +}; + +struct __attribute__((packed)) DoorSensorConfig { + uint8_t enabled = 0; + uint8_t doorAjarTimeout = 0; + uint8_t doorAjarLoggingEnabled = 0; + uint8_t doorStatusMismatchLoggingEnabled = 0; +}; + struct __attribute__((packed)) UpdatedKeypadEntry { uint16_t codeId; uint32_t code; diff --git a/src/NukiLock.cpp b/src/NukiLock.cpp index ef77595a..939c8f5a 100644 --- a/src/NukiLock.cpp +++ b/src/NukiLock.cpp @@ -194,6 +194,24 @@ Nuki::CmdResult NukiLock::setFobAction(const uint8_t fobActionNr, const uint8_t return result; } +Nuki::CmdResult NukiLock::retrieveInternalLogEntries(const uint32_t startIndex, const uint16_t count, const uint8_t sortOrder, bool const totalCount) { + Action action; + unsigned char payload[8] = {0}; + memcpy(payload, &startIndex, 4); + memcpy(&payload[4], &count, 2); + memcpy(&payload[6], &sortOrder, 1); + memcpy(&payload[7], &totalCount, 1); + + action.cmdType = Nuki::CommandType::CommandWithChallengeAndPin; + action.command = Command::RequestInternalLogEntries; + memcpy(action.payload, &payload, sizeof(payload)); + action.payloadLen = sizeof(payload); + + listOfInternalLogEntries.clear(); + + return executeAction(action); +} + Nuki::CmdResult NukiLock::enableDst(const bool enable) { Config oldConfig; Nuki::CmdResult result = requestConfig(&oldConfig); @@ -538,6 +556,30 @@ Nuki::CmdResult NukiLock::setAdvertisingMode(const AdvertisingMode mode) { return result; } +Nuki::CmdResult NukiLock::scanWifi(uint8_t scanDurationSeconds) { + Action action; + unsigned char payload[1] = {0}; + memcpy(payload, &scanDurationSeconds, 1); + + action.cmdType = Nuki::CommandType::CommandWithChallengeAndPin; + action.command = Command::ScanWifi; + memcpy(action.payload, &payload, sizeof(payload)); + action.payloadLen = sizeof(payload); + + listOfWifiScanEntries.clear(); + + Nuki::CmdResult result = executeAction(action); + return result; +} + +void NukiLock::getWifiScanEntries(std::list* wifiScanEntries) { + wifiScanEntries->clear(); + std::list::iterator it = listOfWifiScanEntries.begin(); + while (it != listOfWifiScanEntries.end()) { + wifiScanEntries->push_back(*it); + it++; + } +} Nuki::CmdResult NukiLock::addTimeControlEntry(NewTimeControlEntry newTimeControlEntry) { //TODO verify data validity @@ -626,6 +668,14 @@ void NukiLock::getLogEntries(std::list* requestedLogEntries) { } } +void NukiLock::getInternalLogEntries(std::list* requestedInternalLogEntries) { + requestedInternalLogEntries->clear(); + + for (const auto& it : listOfInternalLogEntries) { + requestedInternalLogEntries->push_back(it); + } +} + Nuki::CmdResult NukiLock::retrieveLogEntries(const uint32_t startIndex, const uint16_t count, const uint8_t sortOrder, bool const totalCount) { Action action; unsigned char payload[8] = {0}; @@ -644,6 +694,18 @@ Nuki::CmdResult NukiLock::retrieveLogEntries(const uint32_t startIndex, const ui return executeAction(action); } +Nuki::CmdResult NukiLock::getAccessoryInfo(const uint8_t accessoryType) { + Action action; + unsigned char payload[1] = {0}; + memcpy(payload, &accessoryType, 1); + + action.cmdType = Nuki::CommandType::CommandWithChallengeAndPin; + action.command = Command::RequestAccessoryInfo; + memcpy(action.payload, &payload, sizeof(payload)); + action.payloadLen = sizeof(payload); + return executeAction(action); +} + bool NukiLock::isBatteryCritical() { if(keyTurnerState.criticalBatteryState != 255) { return ((keyTurnerState.criticalBatteryState & 1) == 1); @@ -828,6 +890,97 @@ void NukiLock::handleReturnMessage(Command returnCode, unsigned char* data, uint } break; } + case Command::InternalLogEntry : { + printBuffer((byte*)data, dataLen, false, "internalLogEntry", debugNukiHexData, logger); + InternalLogEntry internalLogEntry; + memcpy(&internalLogEntry, data, dataLen); + listOfInternalLogEntries.push_back(internalLogEntry); + if (debugNukiReadableData) { + logInternalLogEntry(internalLogEntry, true, logger); + } + break; + } + case Command::MqttConfig : + memcpy(&mqttConfig, data, dataLen); + if (debugNukiReadableData) { + logMqttConfig(mqttConfig, true, logger); + } + printBuffer((byte*)data, dataLen, false, "mqttConfig", debugNukiHexData, logger); + break; + case Command::MqttConfigForMigration : { + memcpy(&mqttConfigForMigration, data, dataLen); + if (debugNukiReadableData) { + logMqttConfigForMigration(mqttConfigForMigration, true, logger); + } + printBuffer((byte*)data, dataLen, false, "mqttConfigForMigration", debugNukiHexData, logger); + break; + } + case Command::WifiScanEntry : { + printBuffer((byte*)data, dataLen, false, "wifiScanEntry", debugNukiHexData, logger); + WifiScanEntry wifiScanEntry; + memcpy(&wifiScanEntry, data, dataLen); + listOfWifiScanEntries.push_back(wifiScanEntry); + if (debugNukiReadableData) { + logWifiScanEntry(wifiScanEntry, true, logger); + } + break; + } + case Command::WifiConfig : { + memcpy(&wifiConfig, data, dataLen); + if (debugNukiReadableData) { + logWifiConfig(wifiConfig, true, logger); + } + printBuffer((byte*)data, dataLen, false, "wifiConfig", debugNukiHexData, logger); + break; + } + case Command::WifiConfigForMigration : { + memcpy(&wifiConfigForMigration, data, dataLen); + if (debugNukiReadableData) { + logWifiConfigForMigration(wifiConfigForMigration, true, logger); + } + printBuffer((byte*)data, dataLen, false, "wifiConfigForMigration", debugNukiHexData, logger); + break; + } + case Command::Keypad2Config : { + memcpy(&keypad2Config, data, dataLen); + if (debugNukiReadableData) { + logKeypad2Config(keypad2Config, true, logger); + } + printBuffer((byte*)data, dataLen, false, "keypad2Config", debugNukiHexData, logger); + break; + } + case Command::GeneralStatistics : { + memcpy(&generalStatistics, data, dataLen); + if (debugNukiReadableData) { + logGeneralStatistics(generalStatistics, true, logger); + } + printBuffer((byte*)data, dataLen, false, "generalStatistics", debugNukiHexData, logger); + break; + } + case Command::DailyStatistics : { + memcpy(&dailyStatistics, data, dataLen); + if (debugNukiReadableData) { + logDailyStatistics(dailyStatistics, true, logger); + } + printBuffer((byte*)data, dataLen, false, "dailyStatistics", debugNukiHexData, logger); + break; + } + case Command::AccessoryInfo : { + memcpy(&accessoryInfo, data, dataLen); + if (debugNukiReadableData) { + logAccessoryInfo(accessoryInfo, true, logger); + } + printBuffer((byte*)data, dataLen, false, "accessoryInfo", debugNukiHexData, logger); + break; + } + case Command::DoorSensorConfig : { + memcpy(&doorSensorConfig, data, dataLen); + if (debugNukiReadableData) { + logDoorSensorConfig(doorSensorConfig, true, logger); + } + printBuffer((byte*)data, dataLen, false, "doorSensorConfig", debugNukiHexData, logger); + break; + } default: NukiBle::handleReturnMessage(returnCode, data, dataLen); } diff --git a/src/NukiLock.h b/src/NukiLock.h index 841aaf8f..f1ea001e 100644 --- a/src/NukiLock.h +++ b/src/NukiLock.h @@ -69,6 +69,22 @@ class NukiLock : public Nuki::NukiBle { */ Nuki::CmdResult requestAdvancedConfig(AdvancedConfig* retrievedAdvancedConfig); + /** + * @brief Request the lock via BLE to send the internal log entries + * + * @param startIndex Startindex of first log msg to be send + * @param count The number of log entries to be read, starting at the specified start index. + * @param sortOrder The desired sort order + * @param totalCount true if a Log Entry Count is requested from the lock + */ + Nuki::CmdResult retrieveInternalLogEntries(const uint32_t startIndex, const uint16_t count, const uint8_t sortOrder, bool const totalCount); + + /** + * @brief Get the Internal Log Entries stored on the esp. Only available after executing retrieveInternalLogEntries. + * + * @param requestedInternalLogEntries list to store the returned internal log entries + */ + void getInternalLogEntries(std::list* requestedInternalLogEntries); /** * @brief Gets the current config from the lock, updates the name parameter and sends the @@ -385,7 +401,6 @@ class NukiLock : public Nuki::NukiBle { */ Nuki::CmdResult setAdvertisingMode(const AdvertisingMode mode); - /** * @brief Sends a new time(d) control entry via BLE to the lock. * This entry is independant of keypad or authorization entries, it will execute the @@ -443,6 +458,27 @@ class NukiLock : public Nuki::NukiBle { Nuki::CmdResult retrieveLogEntries(const uint32_t startIndex, const uint16_t count, const uint8_t sortOrder, const bool totalCount); + /** + * @brief Retrieve information about an accessory + * + * @param accessoryType The accessory type to retrieve information about + */ + Nuki::CmdResult getAccessoryInfo(const uint8_t accessoryType); + + /** + * @brief Scan for WiFi networks + * + * @param scanDurationSeconds Amount of seconds to scan for WiFi networks + */ + Nuki::CmdResult scanWifi(uint8_t scanDurationSeconds = 10); + + /** + * @brief Get the Wifi scan entries stored on the esp (after executing scanWifi) + * + * @param wifiScanEntries list to store the returned Wifi scan entries + */ + void getWifiScanEntries(std::list* wifiScanEntries); + /** * @brief Returns battery critical state parsed from the battery state byte (battery critical byte) * @@ -451,7 +487,7 @@ class NukiLock : public Nuki::NukiBle { * @return true if critical */ bool isBatteryCritical(); - + /** * @brief Returns door sensor battery critical state in case this is supported * @@ -511,9 +547,20 @@ class NukiLock : public Nuki::NukiBle { BatteryReport batteryReport; std::list listOfTimeControlEntries; std::list listOfLogEntries; + std::list listOfInternalLogEntries; + std::list listOfWifiScanEntries; Config config; AdvancedConfig advancedConfig; + MqttConfig mqttConfig; + MqttConfigForMigration mqttConfigForMigration; + WifiConfig wifiConfig; + AccessoryInfo accessoryInfo; + WifiConfigForMigration wifiConfigForMigration; + Keypad2Config keypad2Config; + GeneralStatistics generalStatistics; + DailyStatistics dailyStatistics; + DoorSensorConfig doorSensorConfig; }; } \ No newline at end of file diff --git a/src/NukiLockConstants.h b/src/NukiLockConstants.h index 025b6d9f..0bcff86d 100644 --- a/src/NukiLockConstants.h +++ b/src/NukiLockConstants.h @@ -353,6 +353,19 @@ enum class LoggingType : uint8_t { DoorSensorLoggingEnabled = 0x07 }; +struct __attribute__((packed)) InternalLogEntry { + uint32_t index; + uint16_t timeStampYear; + uint8_t timeStampMonth; + uint8_t timeStampDay; + uint8_t timeStampHour; + uint8_t timeStampMinute; + uint8_t timeStampSecond; + uint32_t authId; + LoggingType loggingType; + uint8_t data[40]; +}; + struct __attribute__((packed)) LogEntry { uint32_t index; uint16_t timeStampYear; diff --git a/src/NukiLockUtils.cpp b/src/NukiLockUtils.cpp index 35a62bfd..0599300d 100644 --- a/src/NukiLockUtils.cpp +++ b/src/NukiLockUtils.cpp @@ -159,72 +159,72 @@ void logLockErrorCode(uint8_t errorCode, bool debug, Print* Log) { void logConfig(Config config, bool debug, Print* Log) { if (debug) { - logMessageVar("nukiId :%d", (unsigned int)config.nukiId, Log, 4); - logMessageVar("name :%s", (const char*)config.name, Log, 4); + logMessageVar("nukiId: %d", (unsigned int)config.nukiId, Log, 4); + logMessageVar("name: %s", (const char*)config.name, Log, 4); logMessage("latitude : Not reported for privacy", Log, 4); logMessage("longitude : Not reported for privacy", Log, 4); - //logMessageVar("latitude :%f", (const float)config.latitude, Log, 4); - //logMessageVar("longitude :%f", (const float)config.longitude, Log, 4); - logMessageVar("autoUnlatch :%d", (unsigned int)config.autoUnlatch, Log, 4); - logMessageVar("pairingEnabled :%d", (unsigned int)config.pairingEnabled, Log, 4); - logMessageVar("buttonEnabled :%d", (unsigned int)config.buttonEnabled, Log, 4); - logMessageVar("ledEnabled :%d", (unsigned int)config.ledEnabled, Log, 4); - logMessageVar("ledBrightness :%d", (unsigned int)config.ledBrightness, Log, 4); - logMessageVar("currentTime Year :%d", (unsigned int)config.currentTimeYear, Log, 4); - logMessageVar("currentTime Month :%d", (unsigned int)config.currentTimeMonth, Log, 4); - logMessageVar("currentTime Day :%d", (unsigned int)config.currentTimeDay, Log, 4); - logMessageVar("currentTime Hour :%d", (unsigned int)config.currentTimeHour, Log, 4); - logMessageVar("currentTime Minute :%d", (unsigned int)config.currentTimeMinute, Log, 4); - logMessageVar("currentTime Second :%d", (unsigned int)config.currentTimeSecond, Log, 4); - logMessageVar("timeZoneOffset :%d", (unsigned int)config.timeZoneOffset, Log, 4); - logMessageVar("dstMode :%d", (unsigned int)config.dstMode, Log, 4); - logMessageVar("hasFob :%d", (unsigned int)config.hasFob, Log, 4); - logMessageVar("fobAction1 :%d", (unsigned int)config.fobAction1, Log, 4); - logMessageVar("fobAction2 :%d", (unsigned int)config.fobAction2, Log, 4); - logMessageVar("fobAction3 :%d", (unsigned int)config.fobAction3, Log, 4); - logMessageVar("singleLock :%d", (unsigned int)config.singleLock, Log, 4); - logMessageVar("advertisingMode :%d", (unsigned int)config.advertisingMode, Log, 4); - logMessageVar("hasKeypad :%d", (unsigned int)config.hasKeypad, Log, 4); + //logMessageVar("latitude: %f", (const float)config.latitude, Log, 4); + //logMessageVar("longitude: %f", (const float)config.longitude, Log, 4); + logMessageVar("autoUnlatch: %d", (unsigned int)config.autoUnlatch, Log, 4); + logMessageVar("pairingEnabled: %d", (unsigned int)config.pairingEnabled, Log, 4); + logMessageVar("buttonEnabled: %d", (unsigned int)config.buttonEnabled, Log, 4); + logMessageVar("ledEnabled: %d", (unsigned int)config.ledEnabled, Log, 4); + logMessageVar("ledBrightness: %d", (unsigned int)config.ledBrightness, Log, 4); + logMessageVar("currentTime Year: %d", (unsigned int)config.currentTimeYear, Log, 4); + logMessageVar("currentTime Month: %d", (unsigned int)config.currentTimeMonth, Log, 4); + logMessageVar("currentTime Day: %d", (unsigned int)config.currentTimeDay, Log, 4); + logMessageVar("currentTime Hour: %d", (unsigned int)config.currentTimeHour, Log, 4); + logMessageVar("currentTime Minute: %d", (unsigned int)config.currentTimeMinute, Log, 4); + logMessageVar("currentTime Second: %d", (unsigned int)config.currentTimeSecond, Log, 4); + logMessageVar("timeZoneOffset: %d", (unsigned int)config.timeZoneOffset, Log, 4); + logMessageVar("dstMode: %d", (unsigned int)config.dstMode, Log, 4); + logMessageVar("hasFob: %d", (unsigned int)config.hasFob, Log, 4); + logMessageVar("fobAction1: %d", (unsigned int)config.fobAction1, Log, 4); + logMessageVar("fobAction2: %d", (unsigned int)config.fobAction2, Log, 4); + logMessageVar("fobAction3: %d", (unsigned int)config.fobAction3, Log, 4); + logMessageVar("singleLock: %d", (unsigned int)config.singleLock, Log, 4); + logMessageVar("advertisingMode: %d", (unsigned int)config.advertisingMode, Log, 4); + logMessageVar("hasKeypad: %d", (unsigned int)config.hasKeypad, Log, 4); if (Log == nullptr) { - log_d("firmwareVersion :%d.%d.%d", config.firmwareVersion[0], config.firmwareVersion[1], config.firmwareVersion[2]); - log_d("hardwareRevision :%d.%d", config.hardwareRevision[0], config.hardwareRevision[1]); + log_d("firmwareVersion: %d.%d.%d", config.firmwareVersion[0], config.firmwareVersion[1], config.firmwareVersion[2]); + log_d("hardwareRevision: %d.%d", config.hardwareRevision[0], config.hardwareRevision[1]); } else { - Log->printf("firmwareVersion :%d.%d.%d", config.firmwareVersion[0], config.firmwareVersion[1], config.firmwareVersion[2]); + Log->printf("firmwareVersion: %d.%d.%d", config.firmwareVersion[0], config.firmwareVersion[1], config.firmwareVersion[2]); Log->println(); - Log->printf("hardwareRevision :%d.%d", config.hardwareRevision[0], config.hardwareRevision[1]); + Log->printf("hardwareRevision: %d.%d", config.hardwareRevision[0], config.hardwareRevision[1]); Log->println(); } - logMessageVar("homeKitStatus :%d", (unsigned int)config.homeKitStatus, Log, 4); - logMessageVar("timeZoneId :%d", (unsigned int)config.timeZoneId, Log, 4); - logMessageVar("deviceType :%d", (unsigned int)config.deviceType, Log, 4); - logMessageVar("wifiCapable :%d", (unsigned int)config.capabilities & 1, Log, 4); - logMessageVar("threadCapable :%d", (unsigned int)(((unsigned int)config.capabilities & 2) != 0 ? 1 : 0), Log, 4); - logMessageVar("hasKeypadV2 :%d", (unsigned int)config.hasKeypadV2, Log, 4); - logMessageVar("matterStatus :%d", (unsigned int)config.matterStatus, Log, 4); - logMessageVar("productVariant :%d", (unsigned int)config.productVariant, Log, 4); + logMessageVar("homeKitStatus: %d", (unsigned int)config.homeKitStatus, Log, 4); + logMessageVar("timeZoneId: %d", (unsigned int)config.timeZoneId, Log, 4); + logMessageVar("deviceType: %d", (unsigned int)config.deviceType, Log, 4); + logMessageVar("wifiCapable: %d", (unsigned int)config.capabilities & 1, Log, 4); + logMessageVar("threadCapable: %d", (unsigned int)(((unsigned int)config.capabilities & 2) != 0 ? 1 : 0), Log, 4); + logMessageVar("hasKeypadV2: %d", (unsigned int)config.hasKeypadV2, Log, 4); + logMessageVar("matterStatus: %d", (unsigned int)config.matterStatus, Log, 4); + logMessageVar("productVariant: %d", (unsigned int)config.productVariant, Log, 4); } } void logNewConfig(NewConfig newConfig, bool debug, Print* Log) { if (debug) { - logMessageVar("name :%s", (const char*)newConfig.name, Log, 4); - logMessageVar("latitude :%f", (const float)newConfig.latitude, Log, 4); - logMessageVar("longitude :%f", (const float)newConfig.longitude, Log, 4); - logMessageVar("autoUnlatch :%d", (unsigned int)newConfig.autoUnlatch, Log, 4); - logMessageVar("pairingEnabled :%d", (unsigned int)newConfig.pairingEnabled, Log, 4); - logMessageVar("buttonEnabled :%d", (unsigned int)newConfig.buttonEnabled, Log, 4); - logMessageVar("ledEnabled :%d", (unsigned int)newConfig.ledEnabled, Log, 4); - logMessageVar("ledBrightness :%d", (unsigned int)newConfig.ledBrightness, Log, 4); - logMessageVar("timeZoneOffset :%d", (unsigned int)newConfig.timeZoneOffset, Log, 4); - logMessageVar("dstMode :%d", (unsigned int)newConfig.dstMode, Log, 4); - logMessageVar("fobAction1 :%d", (unsigned int)newConfig.fobAction1, Log, 4); - logMessageVar("fobAction2 :%d", (unsigned int)newConfig.fobAction2, Log, 4); - logMessageVar("fobAction3 :%d", (unsigned int)newConfig.fobAction3, Log, 4); - logMessageVar("singleLock :%d", (unsigned int)newConfig.singleLock, Log, 4); - logMessageVar("advertisingMode :%d", (unsigned int)newConfig.advertisingMode, Log, 4); - logMessageVar("timeZoneId :%d", (unsigned int)newConfig.timeZoneId, Log, 4); + logMessageVar("name: %s", (const char*)newConfig.name, Log, 4); + logMessageVar("latitude: %f", (const float)newConfig.latitude, Log, 4); + logMessageVar("longitude: %f", (const float)newConfig.longitude, Log, 4); + logMessageVar("autoUnlatch: %d", (unsigned int)newConfig.autoUnlatch, Log, 4); + logMessageVar("pairingEnabled: %d", (unsigned int)newConfig.pairingEnabled, Log, 4); + logMessageVar("buttonEnabled: %d", (unsigned int)newConfig.buttonEnabled, Log, 4); + logMessageVar("ledEnabled: %d", (unsigned int)newConfig.ledEnabled, Log, 4); + logMessageVar("ledBrightness: %d", (unsigned int)newConfig.ledBrightness, Log, 4); + logMessageVar("timeZoneOffset: %d", (unsigned int)newConfig.timeZoneOffset, Log, 4); + logMessageVar("dstMode: %d", (unsigned int)newConfig.dstMode, Log, 4); + logMessageVar("fobAction1: %d", (unsigned int)newConfig.fobAction1, Log, 4); + logMessageVar("fobAction2: %d", (unsigned int)newConfig.fobAction2, Log, 4); + logMessageVar("fobAction3: %d", (unsigned int)newConfig.fobAction3, Log, 4); + logMessageVar("singleLock: %d", (unsigned int)newConfig.singleLock, Log, 4); + logMessageVar("advertisingMode: %d", (unsigned int)newConfig.advertisingMode, Log, 4); + logMessageVar("timeZoneId: %d", (unsigned int)newConfig.timeZoneId, Log, 4); } } @@ -670,62 +670,252 @@ void logLogEntry(LogEntry logEntry, bool debug, Print* Log) { void logAdvancedConfig(AdvancedConfig advancedConfig, bool debug, Print* Log) { if (debug) { - logMessageVar("totalDegrees :%d", (unsigned int)advancedConfig.totalDegrees, Log, 4); - logMessageVar("unlockedPositionOffsetDegrees :%d", (unsigned int)advancedConfig.unlockedPositionOffsetDegrees, Log, 4); - logMessageVar("lockedPositionOffsetDegrees :%f", (const float)advancedConfig.lockedPositionOffsetDegrees, Log, 4); - logMessageVar("singleLockedPositionOffsetDegrees :%f", (const float)advancedConfig.singleLockedPositionOffsetDegrees, Log, 4); - logMessageVar("unlockedToLockedTransitionOffsetDegrees :%d", (unsigned int)advancedConfig.unlockedToLockedTransitionOffsetDegrees, Log, 4); - logMessageVar("lockNgoTimeout :%d", (unsigned int)advancedConfig.lockNgoTimeout, Log, 4); - logMessageVar("singleButtonPressAction :%d", (unsigned int)advancedConfig.singleButtonPressAction, Log, 4); - logMessageVar("doubleButtonPressAction :%d", (unsigned int)advancedConfig.doubleButtonPressAction, Log, 4); - logMessageVar("detachedCylinder :%d", (unsigned int)advancedConfig.detachedCylinder, Log, 4); - logMessageVar("batteryType :%d", (unsigned int)advancedConfig.batteryType, Log, 4); - logMessageVar("automaticBatteryTypeDetection :%d", (unsigned int)advancedConfig.automaticBatteryTypeDetection, Log, 4); - logMessageVar("unlatchDuration :%d", (unsigned int)advancedConfig.unlatchDuration, Log, 4); - logMessageVar("autoLockTimeOut :%d", (unsigned int)advancedConfig.autoLockTimeOut, Log, 4); - logMessageVar("autoUnLockDisabled :%d", (unsigned int)advancedConfig.autoUnLockDisabled, Log, 4); - logMessageVar("nightModeEnabled :%d", (unsigned int)advancedConfig.nightModeEnabled, Log, 4); - logMessageVar("nightModeStartTime Hour :%d", (unsigned int)advancedConfig.nightModeStartTime[0], Log, 4); - logMessageVar("nightModeStartTime Minute :%d", (unsigned int)advancedConfig.nightModeStartTime[1], Log, 4); - logMessageVar("nightModeEndTime Hour :%d", (unsigned int)advancedConfig.nightModeEndTime[0], Log, 4); - logMessageVar("nightModeEndTime Minute :%d", (unsigned int)advancedConfig.nightModeEndTime[1], Log, 4); - logMessageVar("nightModeAutoLockEnabled :%d", (unsigned int)advancedConfig.nightModeAutoLockEnabled, Log, 4); - logMessageVar("nightModeAutoUnlockDisabled :%d", (unsigned int)advancedConfig.nightModeAutoUnlockDisabled, Log, 4); - logMessageVar("nightModeImmediateLockOnStart :%d", (unsigned int)advancedConfig.nightModeImmediateLockOnStart, Log, 4); - logMessageVar("autoLockEnabled :%d", (unsigned int)advancedConfig.autoLockEnabled, Log, 4); - logMessageVar("immediateAutoLockEnabled :%d", (unsigned int)advancedConfig.immediateAutoLockEnabled, Log, 4); - logMessageVar("autoUpdateEnabled :%d", (unsigned int)advancedConfig.autoUpdateEnabled, Log, 4); - logMessageVar("motorSpeed :%d", (unsigned int)advancedConfig.motorSpeed, Log, 4); - logMessageVar("enableSlowSpeedDuringNightMode :%d", (unsigned int)advancedConfig.enableSlowSpeedDuringNightMode, Log, 4); + logMessageVar("totalDegrees: %d", (unsigned int)advancedConfig.totalDegrees, Log, 4); + logMessageVar("unlockedPositionOffsetDegrees: %d", (unsigned int)advancedConfig.unlockedPositionOffsetDegrees, Log, 4); + logMessageVar("lockedPositionOffsetDegrees: %f", (const float)advancedConfig.lockedPositionOffsetDegrees, Log, 4); + logMessageVar("singleLockedPositionOffsetDegrees: %f", (const float)advancedConfig.singleLockedPositionOffsetDegrees, Log, 4); + logMessageVar("unlockedToLockedTransitionOffsetDegrees: %d", (unsigned int)advancedConfig.unlockedToLockedTransitionOffsetDegrees, Log, 4); + logMessageVar("lockNgoTimeout: %d", (unsigned int)advancedConfig.lockNgoTimeout, Log, 4); + logMessageVar("singleButtonPressAction: %d", (unsigned int)advancedConfig.singleButtonPressAction, Log, 4); + logMessageVar("doubleButtonPressAction: %d", (unsigned int)advancedConfig.doubleButtonPressAction, Log, 4); + logMessageVar("detachedCylinder: %d", (unsigned int)advancedConfig.detachedCylinder, Log, 4); + logMessageVar("batteryType: %d", (unsigned int)advancedConfig.batteryType, Log, 4); + logMessageVar("automaticBatteryTypeDetection: %d", (unsigned int)advancedConfig.automaticBatteryTypeDetection, Log, 4); + logMessageVar("unlatchDuration: %d", (unsigned int)advancedConfig.unlatchDuration, Log, 4); + logMessageVar("autoLockTimeOut: %d", (unsigned int)advancedConfig.autoLockTimeOut, Log, 4); + logMessageVar("autoUnLockDisabled: %d", (unsigned int)advancedConfig.autoUnLockDisabled, Log, 4); + logMessageVar("nightModeEnabled: %d", (unsigned int)advancedConfig.nightModeEnabled, Log, 4); + logMessageVar("nightModeStartTime Hour: %d", (unsigned int)advancedConfig.nightModeStartTime[0], Log, 4); + logMessageVar("nightModeStartTime Minute: %d", (unsigned int)advancedConfig.nightModeStartTime[1], Log, 4); + logMessageVar("nightModeEndTime Hour: %d", (unsigned int)advancedConfig.nightModeEndTime[0], Log, 4); + logMessageVar("nightModeEndTime Minute: %d", (unsigned int)advancedConfig.nightModeEndTime[1], Log, 4); + logMessageVar("nightModeAutoLockEnabled: %d", (unsigned int)advancedConfig.nightModeAutoLockEnabled, Log, 4); + logMessageVar("nightModeAutoUnlockDisabled: %d", (unsigned int)advancedConfig.nightModeAutoUnlockDisabled, Log, 4); + logMessageVar("nightModeImmediateLockOnStart: %d", (unsigned int)advancedConfig.nightModeImmediateLockOnStart, Log, 4); + logMessageVar("autoLockEnabled: %d", (unsigned int)advancedConfig.autoLockEnabled, Log, 4); + logMessageVar("immediateAutoLockEnabled: %d", (unsigned int)advancedConfig.immediateAutoLockEnabled, Log, 4); + logMessageVar("autoUpdateEnabled: %d", (unsigned int)advancedConfig.autoUpdateEnabled, Log, 4); + logMessageVar("motorSpeed: %d", (unsigned int)advancedConfig.motorSpeed, Log, 4); + logMessageVar("enableSlowSpeedDuringNightMode: %d", (unsigned int)advancedConfig.enableSlowSpeedDuringNightMode, Log, 4); } } void logNewAdvancedConfig(NewAdvancedConfig newAdvancedConfig, bool debug, Print* Log) { if (debug) { - logMessageVar("unlockedPositionOffsetDegrees :%d", (unsigned int)newAdvancedConfig.unlockedPositionOffsetDegrees, Log, 4); - logMessageVar("lockedPositionOffsetDegrees :%f", (const float)newAdvancedConfig.lockedPositionOffsetDegrees, Log, 4); - logMessageVar("singleLockedPositionOffsetDegrees :%f", (const float)newAdvancedConfig.singleLockedPositionOffsetDegrees, Log, 4); - logMessageVar("unlockedToLockedTransitionOffsetDegrees :%d", (unsigned int)newAdvancedConfig.unlockedToLockedTransitionOffsetDegrees, Log, 4); - logMessageVar("lockNgoTimeout :%d", (unsigned int)newAdvancedConfig.lockNgoTimeout, Log, 4); - logMessageVar("singleButtonPressAction :%d", (unsigned int)newAdvancedConfig.singleButtonPressAction, Log, 4); - logMessageVar("doubleButtonPressAction :%d", (unsigned int)newAdvancedConfig.doubleButtonPressAction, Log, 4); - logMessageVar("detachedCylinder :%d", (unsigned int)newAdvancedConfig.detachedCylinder, Log, 4); - logMessageVar("batteryType :%d", (unsigned int)newAdvancedConfig.batteryType, Log, 4); - logMessageVar("automaticBatteryTypeDetection :%d", (unsigned int)newAdvancedConfig.automaticBatteryTypeDetection, Log, 4); - logMessageVar("unlatchDuration :%d", (unsigned int)newAdvancedConfig.unlatchDuration, Log, 4); - logMessageVar("autoUnLockTimeOut :%d", (unsigned int)newAdvancedConfig.autoLockTimeOut, Log, 4); - logMessageVar("autoUnLockDisabled :%d", (unsigned int)newAdvancedConfig.autoUnLockDisabled, Log, 4); - logMessageVar("nightModeEnabled :%d", (unsigned int)newAdvancedConfig.nightModeEnabled, Log, 4); - logMessageVar("nightModeStartTime Hour :%d", (unsigned int)newAdvancedConfig.nightModeStartTime[0], Log, 4); - logMessageVar("nightModeStartTime Minute :%d", (unsigned int)newAdvancedConfig.nightModeStartTime[1], Log, 4); - logMessageVar("nightModeEndTime Hour :%d", (unsigned int)newAdvancedConfig.nightModeEndTime[0], Log, 4); - logMessageVar("nightModeEndTime Minute :%d", (unsigned int)newAdvancedConfig.nightModeEndTime[1], Log, 4); - logMessageVar("nightModeAutoLockEnabled :%d", (unsigned int)newAdvancedConfig.nightModeAutoLockEnabled, Log, 4); - logMessageVar("nightModeAutoUnlockDisabled :%d", (unsigned int)newAdvancedConfig.nightModeAutoUnlockDisabled, Log, 4); - logMessageVar("nightModeImmediateLockOnStart :%d", (unsigned int)newAdvancedConfig.nightModeImmediateLockOnStart, Log, 4); - logMessageVar("autoLockEnabled :%d", (unsigned int)newAdvancedConfig.autoLockEnabled, Log, 4); - logMessageVar("immediateAutoLockEnabled :%d", (unsigned int)newAdvancedConfig.immediateAutoLockEnabled, Log, 4); - logMessageVar("autoUpdateEnabled :%d", (unsigned int)newAdvancedConfig.autoUpdateEnabled, Log, 4); + logMessageVar("unlockedPositionOffsetDegrees: %d", (unsigned int)newAdvancedConfig.unlockedPositionOffsetDegrees, Log, 4); + logMessageVar("lockedPositionOffsetDegrees: %f", (const float)newAdvancedConfig.lockedPositionOffsetDegrees, Log, 4); + logMessageVar("singleLockedPositionOffsetDegrees: %f", (const float)newAdvancedConfig.singleLockedPositionOffsetDegrees, Log, 4); + logMessageVar("unlockedToLockedTransitionOffsetDegrees: %d", (unsigned int)newAdvancedConfig.unlockedToLockedTransitionOffsetDegrees, Log, 4); + logMessageVar("lockNgoTimeout: %d", (unsigned int)newAdvancedConfig.lockNgoTimeout, Log, 4); + logMessageVar("singleButtonPressAction: %d", (unsigned int)newAdvancedConfig.singleButtonPressAction, Log, 4); + logMessageVar("doubleButtonPressAction: %d", (unsigned int)newAdvancedConfig.doubleButtonPressAction, Log, 4); + logMessageVar("detachedCylinder: %d", (unsigned int)newAdvancedConfig.detachedCylinder, Log, 4); + logMessageVar("batteryType: %d", (unsigned int)newAdvancedConfig.batteryType, Log, 4); + logMessageVar("automaticBatteryTypeDetection: %d", (unsigned int)newAdvancedConfig.automaticBatteryTypeDetection, Log, 4); + logMessageVar("unlatchDuration: %d", (unsigned int)newAdvancedConfig.unlatchDuration, Log, 4); + logMessageVar("autoUnLockTimeOut: %d", (unsigned int)newAdvancedConfig.autoLockTimeOut, Log, 4); + logMessageVar("autoUnLockDisabled: %d", (unsigned int)newAdvancedConfig.autoUnLockDisabled, Log, 4); + logMessageVar("nightModeEnabled: %d", (unsigned int)newAdvancedConfig.nightModeEnabled, Log, 4); + logMessageVar("nightModeStartTime Hour: %d", (unsigned int)newAdvancedConfig.nightModeStartTime[0], Log, 4); + logMessageVar("nightModeStartTime Minute: %d", (unsigned int)newAdvancedConfig.nightModeStartTime[1], Log, 4); + logMessageVar("nightModeEndTime Hour: %d", (unsigned int)newAdvancedConfig.nightModeEndTime[0], Log, 4); + logMessageVar("nightModeEndTime Minute: %d", (unsigned int)newAdvancedConfig.nightModeEndTime[1], Log, 4); + logMessageVar("nightModeAutoLockEnabled: %d", (unsigned int)newAdvancedConfig.nightModeAutoLockEnabled, Log, 4); + logMessageVar("nightModeAutoUnlockDisabled: %d", (unsigned int)newAdvancedConfig.nightModeAutoUnlockDisabled, Log, 4); + logMessageVar("nightModeImmediateLockOnStart: %d", (unsigned int)newAdvancedConfig.nightModeImmediateLockOnStart, Log, 4); + logMessageVar("autoLockEnabled: %d", (unsigned int)newAdvancedConfig.autoLockEnabled, Log, 4); + logMessageVar("immediateAutoLockEnabled: %d", (unsigned int)newAdvancedConfig.immediateAutoLockEnabled, Log, 4); + logMessageVar("autoUpdateEnabled: %d", (unsigned int)newAdvancedConfig.autoUpdateEnabled, Log, 4); + } +} + +void logWifiScanEntry(WifiScanEntry wifiScanEntry, bool debug, Print* Log) { + if (debug) { + logMessageVar("ssid: %s", (const char*)wifiScanEntry.ssid, Log, 4); + logMessageVar("type: %d", (unsigned int)wifiScanEntry.type, Log, 4); + logMessageVar("signal raw: %d", (unsigned int)wifiScanEntry.signal, Log, 4); + logMessageVar("signal: %d", (unsigned int)(wifiScanEntry.signal & 255), Log, 4); + } +} + +void logMqttConfig(MqttConfig mqttConfig, bool debug, Print* Log) { + if (debug) { + logMessageVar("enabled: %d", (unsigned int)mqttConfig.enabled, Log, 4); + logMessageVar("hostName: %s", (const char*)mqttConfig.hostName, Log, 4); + logMessageVar("userName: %s", (const char*)mqttConfig.userName, Log, 4); + logMessageVar("secureConnection: %d", (unsigned int)mqttConfig.secureConnection, Log, 4); + logMessageVar("autoDiscovery: %d", (unsigned int)mqttConfig.autoDiscovery, Log, 4); + logMessageVar("lockingEnabled: %d", (unsigned int)mqttConfig.lockingEnabled, Log, 4); + } +} + +void logMqttConfigForMigration(MqttConfigForMigration mqttConfigForMigration, bool debug, Print* Log) { + if (debug) { + logMessageVar("enabled: %d", (unsigned int)mqttConfigForMigration.enabled, Log, 4); + logMessageVar("hostName: %s", (const char*)mqttConfigForMigration.hostName, Log, 4); + logMessageVar("userName: %s", (const char*)mqttConfigForMigration.userName, Log, 4); + logMessageVar("secureConnection: %d", (unsigned int)mqttConfigForMigration.secureConnection, Log, 4); + logMessageVar("autoDiscovery: %d", (unsigned int)mqttConfigForMigration.autoDiscovery, Log, 4); + logMessageVar("lockingEnabled: %d", (unsigned int)mqttConfigForMigration.lockingEnabled, Log, 4); + logMessageVar("passphrase: %s", (const char*)mqttConfigForMigration.passphrase, Log, 4); + } +} + +void logWifiConfig(WifiConfig wifiConfig, bool debug, Print* Log) { + if (debug) { + logMessageVar("serverBridgeId: %d", (unsigned int)wifiConfig.serverBridgeId, Log, 4); + logMessageVar("wifiEnabled: %d", (unsigned int)wifiConfig.wifiEnabled, Log, 4); + logMessageVar("wifiExpertSettings composed value: %d", (unsigned int)wifiConfig.wifiExpertSettings, Log, 4); + logMessageVar("expertSettingsMode: %d", (unsigned int)(wifiConfig.wifiExpertSettings & 3), Log, 4); + logMessageVar("broadcastFilterSettings: %d", (unsigned int)((wifiConfig.wifiExpertSettings >> 2) & 3), Log, 4); + logMessageVar("dtimSkipSettings: %d", (unsigned int)((wifiConfig.wifiExpertSettings >> 4) & 7), Log, 4); + logMessageVar("sseSkipSettings: %d", (unsigned int)((wifiConfig.wifiExpertSettings >> 7) & 7), Log, 4); + logMessageVar("powersafeMode: %d", (unsigned int)((wifiConfig.wifiExpertSettings >> 10) & 3), Log, 4); + logMessageVar("activePingEnabled: %d", (unsigned int)((wifiConfig.wifiExpertSettings >> 12) & 1), Log, 4); + } +} + +void logWifiConfigForMigration(WifiConfigForMigration wifiConfigForMigration, bool debug, Print* Log) { + if (debug) { + logMessageVar("ssid: %s", (const char*)wifiConfigForMigration.ssid, Log, 4); + logMessageVar("type: %d", (unsigned int)wifiConfigForMigration.type, Log, 4); + logMessageVar("passphrase: %s", (const char*)wifiConfigForMigration.passphrase, Log, 4); + } +} + +void logKeypad2Config(Keypad2Config keypad2Config, bool debug, Print* Log) { + if (debug) { + logMessageVar("updatePending: %d", (unsigned int)keypad2Config.updatePending, Log, 4); + logMessageVar("ledBrightness: %d", (unsigned int)keypad2Config.ledBrightness, Log, 4); + logMessageVar("batteryType: %d", (unsigned int)keypad2Config.batteryType, Log, 4); + logMessageVar("buttonMode: %d", (unsigned int)keypad2Config.buttonMode, Log, 4); + logMessageVar("lockAction: %d", (unsigned int)keypad2Config.lockAction, Log, 4); + } +} + +void logDoorSensorConfig(DoorSensorConfig doorSensorConfig, bool debug, Print* Log) { + if (debug) { + logMessageVar("enabled: %d", (unsigned int)doorSensorConfig.enabled, Log, 4); + logMessageVar("doorAjarTimeout: %d", (unsigned int)doorSensorConfig.doorAjarTimeout, Log, 4); + logMessageVar("doorAjarLoggingEnabled: %d", (unsigned int)doorSensorConfig.doorAjarLoggingEnabled, Log, 4); + logMessageVar("doorStatusMismatchLoggingEnabled: %d", (unsigned int)doorSensorConfig.doorStatusMismatchLoggingEnabled, Log, 4); + } +} + +void logFingerprintEntry(FingerprintEntry fingerprintEntry, bool debug, Print* Log) { + if (debug) { + String hexByte; + char tmp[16]; + + for (size_t i = 0; i < 32; i += 1) { + sprintf(tmp, "%02x", fingerprintEntry.fingerprintId[i]); + hexByte += strtol((const char*)tmp, nullptr, 16); + } + logMessageVar("fingerprintId:%s", (const char*)hexByte.c_str(), Log, 4); + logMessageVar("keypadCodeId: %d", (unsigned int)fingerprintEntry.keypadCodeId, Log, 4); + logMessageVar("name:%s", (const char*)fingerprintEntry.name, Log, 4); + } +} + +void logAccessoryInfo(AccessoryInfo accessoryInfo, bool debug, Print* Log) { + if (debug) { + logMessageVar("dateYear: %d", (unsigned int)accessoryInfo.dateYear, Log, 4); + logMessageVar("dateMonth: %d", (unsigned int)accessoryInfo.dateMonth, Log, 4); + logMessageVar("dateDay: %d", (unsigned int)accessoryInfo.dateDay, Log, 4); + logMessageVar("dateHour: %d", (unsigned int)accessoryInfo.dateHour, Log, 4); + logMessageVar("dateMinute: %d", (unsigned int)accessoryInfo.dateMinute, Log, 4); + logMessageVar("dateSecond: %d", (unsigned int)accessoryInfo.dateSecond, Log, 4); + logMessageVar("accessoryNukiId: %d", (unsigned int)accessoryInfo.accessoryNukiId, Log, 4); + logMessageVar("accessoryType: %d", (unsigned int)accessoryInfo.accessoryType, Log, 4); + if (Log == nullptr) { + log_d("firmwareVersion: %d.%d.%d", accessoryInfo.firmwareVersion[0], accessoryInfo.firmwareVersion[1], accessoryInfo.firmwareVersion[2]); + log_d("hardwareRevision: %d.%d", accessoryInfo.hardwareRevision[0], accessoryInfo.hardwareRevision[1]); + } + else + { + Log->printf("firmwareVersion: %d.%d.%d", accessoryInfo.firmwareVersion[0], accessoryInfo.firmwareVersion[1], accessoryInfo.firmwareVersion[2]); + Log->println(); + Log->printf("hardwareRevision: %d.%d", accessoryInfo.hardwareRevision[0], accessoryInfo.hardwareRevision[1]); + Log->println(); + } + logMessageVar("productVariantDifferentiator: %d", (unsigned int)accessoryInfo.productVariantDifferentiator, Log, 4); + logMessageVar("mostRecentBatteryVoltage: %d", (unsigned int)accessoryInfo.mostRecentBatteryVoltage, Log, 4); + logMessageVar("mostRecentTemperature: %d", (unsigned int)accessoryInfo.mostRecentTemperature, Log, 4); + } +} + +void logDailyStatistics(DailyStatistics dailyStatistics, bool debug, Print* Log) { + if (debug) { + logMessageVar("dateYear: %d", (unsigned int)dailyStatistics.dateYear, Log, 4); + logMessageVar("dateMonth: %d", (unsigned int)dailyStatistics.dateMonth, Log, 4); + logMessageVar("dateDay: %d", (unsigned int)dailyStatistics.dateDay, Log, 4); + //logMessageVar("dateHour: %d", (unsigned int)dailyStatistics.dateHour, Log, 4); + //logMessageVar("dateMinute: %d", (unsigned int)dailyStatistics.dateMinute, Log, 4); + //logMessageVar("dateSecond: %d", (unsigned int)dailyStatistics.dateSecond, Log, 4); + logMessageVar("version: %d", (unsigned int)dailyStatistics.version, Log, 4); + logMessageVar("countSuccessfulLockActions: %d", (unsigned int)dailyStatistics.countSuccessfulLockActions, Log, 4); + logMessageVar("countErroneousLockActions: %d", (unsigned int)dailyStatistics.countErroneousLockActions, Log, 4); + logMessageVar("avgCurrentConsumptionLock: %d", (unsigned int)dailyStatistics.avgCurrentConsumptionLock, Log, 4); + logMessageVar("maxCurrentConsumptionLock: %d", (unsigned int)dailyStatistics.maxCurrentConsumptionLock, Log, 4); + logMessageVar("batteryMinStartVoltageLock: %d", (unsigned int)dailyStatistics.batteryMinStartVoltageLock, Log, 4); + logMessageVar("countSuccessfulUnlatchActions: %d", (unsigned int)dailyStatistics.countSuccessfulUnlatchActions, Log, 4); + logMessageVar("countErroneousUnlatchActions: %d", (unsigned int)dailyStatistics.countErroneousUnlatchActions, Log, 4); + logMessageVar("avgCurrentConsumptionUnlatch: %d", (unsigned int)dailyStatistics.avgCurrentConsumptionUnlatch, Log, 4); + logMessageVar("maxCurrentConsumptionUnlatch: %d", (unsigned int)dailyStatistics.maxCurrentConsumptionUnlatch, Log, 4); + logMessageVar("batteryMinStartVoltageUnlatch: %d", (unsigned int)dailyStatistics.batteryMinStartVoltageUnlatch, Log, 4); + logMessageVar("incomingCommands: %d", (unsigned int)dailyStatistics.incomingCommands, Log, 4); + logMessageVar("outgoingCommands: %d", (unsigned int)dailyStatistics.outgoingCommands, Log, 4); + logMessageVar("maxTemperature: %d", (unsigned int)dailyStatistics.maxTemperature, Log, 4); + logMessageVar("minTemperature: %d", (unsigned int)dailyStatistics.minTemperature, Log, 4); + logMessageVar("avgTemperature: %d", (unsigned int)dailyStatistics.avgTemperature, Log, 4); + logMessageVar("numDoorSensorStatusChanges: %d", (unsigned int)dailyStatistics.numDoorSensorStatusChanges, Log, 4); + logMessageVar("maxBatteryPercentage: %d", (unsigned int)dailyStatistics.maxBatteryPercentage, Log, 4); + logMessageVar("minBatteryPercentage: %d", (unsigned int)dailyStatistics.minBatteryPercentage, Log, 4); + logMessageVar("idleTime: %d", (unsigned int)dailyStatistics.idleTime, Log, 4); + logMessageVar("connectionTime: %d", (unsigned int)dailyStatistics.connectionTime, Log, 4); + logMessageVar("actionTime: %d", (unsigned int)dailyStatistics.actionTime, Log, 4); + } +} + +void logGeneralStatistics(GeneralStatistics generalStatistics, bool debug, Print* Log) { + if (debug) { + logMessageVar("version: %d", (unsigned int)generalStatistics.version, Log, 4); + logMessageVar("firstCalibrationYear: %d", (unsigned int)generalStatistics.firstCalibrationYear, Log, 4); + logMessageVar("firstCalibrationMonth: %d", (unsigned int)generalStatistics.firstCalibrationMonth, Log, 4); + logMessageVar("firstCalibrationDay: %d", (unsigned int)generalStatistics.firstCalibrationDay, Log, 4); + logMessageVar("calibrationCount: %d", (unsigned int)generalStatistics.calibrationCount, Log, 4); + logMessageVar("lockActionCount: %d", (unsigned int)generalStatistics.lockActionCount, Log, 4); + logMessageVar("unlatchCount: %d", (unsigned int)generalStatistics.unlatchCount, Log, 4); + logMessageVar("lastRebootDateYear: %d", (unsigned int)generalStatistics.lastRebootDateYear, Log, 4); + logMessageVar("lastRebootDateMonth: %d", (unsigned int)generalStatistics.lastRebootDateMonth, Log, 4); + logMessageVar("lastRebootDateDay: %d", (unsigned int)generalStatistics.lastRebootDateDay, Log, 4); + logMessageVar("lastRebootDateHour: %d", (unsigned int)generalStatistics.lastRebootDateHour, Log, 4); + logMessageVar("lastRebootDateMinute: %d", (unsigned int)generalStatistics.lastRebootDateMinute, Log, 4); + logMessageVar("lastRebootDateSecond: %d", (unsigned int)generalStatistics.lastRebootDateSecond, Log, 4); + logMessageVar("lastChargeDateYear: %d", (unsigned int)generalStatistics.lastChargeDateYear, Log, 4); + logMessageVar("lastChargeDateMonth: %d", (unsigned int)generalStatistics.lastChargeDateMonth, Log, 4); + logMessageVar("lastChargeDateDay: %d", (unsigned int)generalStatistics.lastChargeDateDay, Log, 4); + logMessageVar("lastChargeDateHour: %d", (unsigned int)generalStatistics.lastChargeDateHour, Log, 4); + logMessageVar("lastChargeDateMinute: %d", (unsigned int)generalStatistics.lastChargeDateMinute, Log, 4); + logMessageVar("lastChargeDateSecond: %d", (unsigned int)generalStatistics.lastChargeDateSecond, Log, 4); + logMessageVar("initialBatteryVoltage: %d", (unsigned int)generalStatistics.initialBatteryVoltage, Log, 4); + logMessageVar("numActionsDuringBatteryCycle: %d", (unsigned int)generalStatistics.numActionsDuringBatteryCycle, Log, 4); + logMessageVar("numUnexpectedReboots: %d", (unsigned int)generalStatistics.numUnexpectedReboots, Log, 4); + } +} + +void logInternalLogEntry(InternalLogEntry internalLogEntry, bool debug, Print* Log) { + if (debug) { + if (Log == nullptr) { + log_d("[%d] type:%d authId:%d %d-%d-%d %d:%d:%d ", internalLogEntry.index, internalLogEntry.loggingType, internalLogEntry.authId, internalLogEntry.timeStampYear, internalLogEntry.timeStampMonth, internalLogEntry.timeStampDay, internalLogEntry.timeStampHour, internalLogEntry.timeStampMinute, internalLogEntry.timeStampSecond); + } + else + { + Log->printf("[%d] type:%d authId:%d %d-%d-%d %d:%d:%d ", internalLogEntry.index, internalLogEntry.loggingType, internalLogEntry.authId, internalLogEntry.timeStampYear, internalLogEntry.timeStampMonth, internalLogEntry.timeStampDay, internalLogEntry.timeStampHour, internalLogEntry.timeStampMinute, internalLogEntry.timeStampSecond);; + Log->println(); + } + + logMessageVar("data: %d", (unsigned int)internalLogEntry.data, Log, 4); } } diff --git a/src/NukiLockUtils.h b/src/NukiLockUtils.h index 5b556048..a6b64a0b 100644 --- a/src/NukiLockUtils.h +++ b/src/NukiLockUtils.h @@ -42,6 +42,18 @@ void logBatteryReport(BatteryReport batteryReport, bool debug = false, Print* Lo void logLogEntry(LogEntry logEntry, bool debug = false, Print* Log = nullptr); void logAdvancedConfig(AdvancedConfig advancedConfig, bool debug = false, Print* Log = nullptr); void logNewAdvancedConfig(NewAdvancedConfig newAdvancedConfig, bool debug = false, Print* Log = nullptr); +void logMqttConfig(MqttConfig mqttConfig, bool debug = false, Print* Log = nullptr); +void logMqttConfigForMigration(MqttConfigForMigration mqttConfigForMigration, bool debug = false, Print* Log = nullptr); +void logWifiScanEntry(WifiScanEntry wifiScanEntry, bool debug = false, Print* Log = nullptr); +void logKeypad2Config(Keypad2Config keypad2Config, bool debug = false, Print* Log = nullptr); +void logDoorSensorConfig(DoorSensorConfig doorSensorConfig, bool debug = false, Print* Log = nullptr); +void logWifiConfig(WifiConfig wifiConfig, bool debug = false, Print* Log = nullptr); +void logWifiConfigForMigration(WifiConfigForMigration wifiConfigForMigration, bool debug = false, Print* Log = nullptr); +void logGeneralStatistics(GeneralStatistics generalStatistics, bool debug = false, Print* Log = nullptr); +void logDailyStatistics(DailyStatistics dailyStatistics, bool debug = false, Print* Log = nullptr); +void logFingerprintEntry(FingerprintEntry fingerprintEntry, bool debug = false, Print* Log = nullptr); +void logInternalLogEntry(InternalLogEntry internalLogEntry, bool debug = false, Print* Log = nullptr); +void logAccessoryInfo(AccessoryInfo accessoryInfo, bool debug = false, Print* Log = nullptr); void logMessageVar(const char* message, unsigned int var, Print* Log = nullptr, int level = 4); void logMessageVar(const char* message, const char* var, Print* Log = nullptr, int level = 4); void logMessageVar(const char* message, const float var, Print* Log = nullptr, int level = 4); diff --git a/src/NukiOpenerUtils.cpp b/src/NukiOpenerUtils.cpp index 8fd5c8d9..d45523a0 100644 --- a/src/NukiOpenerUtils.cpp +++ b/src/NukiOpenerUtils.cpp @@ -200,18 +200,18 @@ void logConfig(Config config, bool debug, Print* Log) { void logNewConfig(NewConfig newConfig, bool debug, Print* Log) { if (debug) { - logMessageVar("name :%s", (const char*)newConfig.name, Log, 4); - logMessageVar("latitude :%f", (const float)newConfig.latitude, Log, 4); - logMessageVar("longitude :%f", (const float)newConfig.longitude, Log, 4); - logMessageVar("pairingEnabled :%d", (unsigned int)newConfig.pairingEnabled, Log, 4); - logMessageVar("buttonEnabled :%d", (unsigned int)newConfig.buttonEnabled, Log, 4); - logMessageVar("timeZoneOffset :%d", (unsigned int)newConfig.timeZoneOffset, Log, 4); - logMessageVar("dstMode :%d", (unsigned int)newConfig.dstMode, Log, 4); - logMessageVar("fobAction1 :%d", (unsigned int)newConfig.fobAction1, Log, 4); - logMessageVar("fobAction2 :%d", (unsigned int)newConfig.fobAction2, Log, 4); - logMessageVar("fobAction3 :%d", (unsigned int)newConfig.fobAction3, Log, 4); - logMessageVar("advertisingMode :%d", (unsigned int)newConfig.advertisingMode, Log, 4); - logMessageVar("timeZoneId :%d", (unsigned int)newConfig.timeZoneId, Log, 4); + logMessageVar("name: %s", (const char*)newConfig.name, Log, 4); + logMessageVar("latitude: %f", (const float)newConfig.latitude, Log, 4); + logMessageVar("longitude: %f", (const float)newConfig.longitude, Log, 4); + logMessageVar("pairingEnabled: %d", (unsigned int)newConfig.pairingEnabled, Log, 4); + logMessageVar("buttonEnabled: %d", (unsigned int)newConfig.buttonEnabled, Log, 4); + logMessageVar("timeZoneOffset: %d", (unsigned int)newConfig.timeZoneOffset, Log, 4); + logMessageVar("dstMode: %d", (unsigned int)newConfig.dstMode, Log, 4); + logMessageVar("fobAction1: %d", (unsigned int)newConfig.fobAction1, Log, 4); + logMessageVar("fobAction2: %d", (unsigned int)newConfig.fobAction2, Log, 4); + logMessageVar("fobAction3: %d", (unsigned int)newConfig.fobAction3, Log, 4); + logMessageVar("advertisingMode: %d", (unsigned int)newConfig.advertisingMode, Log, 4); + logMessageVar("timeZoneId: %d", (unsigned int)newConfig.timeZoneId, Log, 4); } } From 893b6bb7f0768bb474d738b437b37813d4112e4a Mon Sep 17 00:00:00 2001 From: iranl Date: Sat, 17 May 2025 21:18:18 +0200 Subject: [PATCH 2/4] Delete main.cpp --- src/main.cpp | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/main.cpp diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index 20794354..00000000 --- a/src/main.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "../examples/NukiSmartlockTest.h" \ No newline at end of file From 01c81b52b2ede42d8742dd0b5dff7e7b5813cf4d Mon Sep 17 00:00:00 2001 From: iranl Date: Wed, 18 Jun 2025 12:12:02 +0200 Subject: [PATCH 3/4] C5 connect fix --- src/NukiBle.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/NukiBle.cpp b/src/NukiBle.cpp index c3d78f9b..16e2fe55 100644 --- a/src/NukiBle.cpp +++ b/src/NukiBle.cpp @@ -298,7 +298,10 @@ bool NukiBle::connectBle(const BLEAddress bleAddress, bool pairing) { pClient = NimBLEDevice::createClient(); pClient->setClientCallbacks(this); - pClient->setConnectionParams(12,12,0,600,64,64); + #if !defined(CONFIG_IDF_TARGET_ESP32C5) + //DISABLE FOR ALL ESPS FOR NOW BASED ON ISSUES WITH C5 (2025-06-18) + //pClient->setConnectionParams(12,12,0,600,64,64); + #endif #ifndef NUKI_USE_LATEST_NIMBLE if (logger == nullptr) { log_d("[%s] Connect timeout %d s", deviceName.c_str(), connectTimeoutSec); From 98872d9004118f1ba2cb3685a30863eb19930cda Mon Sep 17 00:00:00 2001 From: iranl Date: Fri, 20 Jun 2025 09:25:46 +0200 Subject: [PATCH 4/4] Improve connection --- src/NukiBle.cpp | 545 ++++++++++++++++-------------------------------- src/NukiBle.h | 31 ++- src/NukiBle.hpp | 175 ++++++---------- 3 files changed, 256 insertions(+), 495 deletions(-) diff --git a/src/NukiBle.cpp b/src/NukiBle.cpp index 16e2fe55..ab08f6d7 100644 --- a/src/NukiBle.cpp +++ b/src/NukiBle.cpp @@ -22,12 +22,8 @@ #include "sodium/crypto_box.h" #include "NimBLEBeacon.h" -#define NUKI_SEMAPHORE_TIMEOUT 1000 - namespace Nuki { -const char* NUKI_SEMAPHORE_OWNER = "Nuki"; - NukiBle::NukiBle(const std::string& deviceName, const uint32_t deviceId, const NimBLEUUID pairingServiceUUID, @@ -66,7 +62,6 @@ NukiBle::NukiBle(const std::string& deviceName, #ifdef DEBUG_NUKI_COMMAND debugNukiCommand = true; #endif - } NukiBle::~NukiBle() { @@ -87,20 +82,36 @@ void NukiBle::initialize(bool initAltConnect) { NimBLEDevice::init(deviceName); } - if (!initAltConnect) { - pClient = NimBLEDevice::createClient(); - pClient->setClientCallbacks(this); - #ifdef NUKI_USE_LATEST_NIMBLE - pClient->setConnectTimeout(connectTimeoutSec * 1000); - #else - pClient->setConnectTimeout(connectTimeoutSec); - #endif + pClient = NimBLEDevice::createClient(); + pClient->setClientCallbacks(this); + #if !defined(CONFIG_IDF_TARGET_ESP32C5) + //DISABLE FOR ALL ESPS FOR NOW BASED ON ISSUES WITH C5 (2025-06-18) + //pClient->setConnectionParams(12,12,0,600,64,64); + #endif + #ifndef NUKI_USE_LATEST_NIMBLE + if (logger == nullptr) { + log_d("[%s] Connect timeout %d s", deviceName.c_str(), connectTimeoutSec); } else { - altConnect = true; + logger->printf("[%s] Connect timeout %d s\r\n", deviceName.c_str(), connectTimeoutSec); } + pClient->setConnectTimeout(connectTimeoutSec); + #else + if (logger == nullptr) { + log_d("[%s] Connect timeout %d ms", deviceName.c_str(), connectTimeoutSec * 1000); + } + else + { + logger->printf("[%s] Connect timeout %d ms\r\n", deviceName.c_str(), connectTimeoutSec * 1000); + } + pClient->setConnectTimeout(connectTimeoutSec * 1000); + #endif + isPaired = retrieveCredentials(); + + using namespace std::placeholders; + callback = std::bind(&NukiBle::notifyCallback, this, _1, _2, _3, _4); } #ifdef NUKI_USE_LATEST_NIMBLE @@ -233,237 +244,85 @@ void NukiBle::resetHost() { } bool NukiBle::connectBle(const BLEAddress bleAddress, bool pairing) { - if (altConnect) { - connecting = true; - bleScanner->enableScanning(false); - pClient = nullptr; - - if (debugNukiConnect) { - #if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)) - logMessageVar("connecting within: %s", pcTaskGetTaskName(xTaskGetCurrentTaskHandle())); - #else - logMessageVar("connecting within: %s", pcTaskGetName(xTaskGetCurrentTaskHandle())); - #endif - } + connecting = true; + bleScanner->enableScanning(false); - uint8_t connectRetry = 0; - - while (connectRetry < connectRetries) { - #ifdef NUKI_USE_LATEST_NIMBLE - if(NimBLEDevice::getCreatedClientCount()) - #else - if(NimBLEDevice::getClientListSize()) - #endif - { - pClient = NimBLEDevice::getClientByPeerAddress(bleAddress); - if(pClient){ - if(!pClient->isConnected()) { - if(!pClient->connect(bleAddress, refreshServices)) { - if (debugNukiConnect) { - logMessageVar("[%s] Reconnect failed", deviceName.c_str()); - } - connectRetry++; - #ifndef NUKI_NO_WDT_RESET - esp_task_wdt_reset(); - #endif - delay(10); - continue; - } else { - refreshServices = false; - } - if (debugNukiConnect) { - logMessageVar("[%s] Reconnect success", deviceName.c_str()); - } - } - } - } + if (debugNukiConnect) { + #if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)) + logMessageVar("connecting within: %s", pcTaskGetTaskName(xTaskGetCurrentTaskHandle())); + #else + logMessageVar("connecting within: %s", pcTaskGetName(xTaskGetCurrentTaskHandle())); + #endif + } - if(!pClient) { - #ifdef NUKI_USE_LATEST_NIMBLE - if(NimBLEDevice::getCreatedClientCount() >= NIMBLE_MAX_CONNECTIONS) - #else - if(NimBLEDevice::getClientListSize() >= NIMBLE_MAX_CONNECTIONS) - #endif - { - if (debugNukiConnect) { - logMessageVar("[%s] Max clients reached - no more connections available", deviceName.c_str()); - } - connectRetry++; - #ifndef NUKI_NO_WDT_RESET - esp_task_wdt_reset(); - #endif - delay(10); - continue; - } + uint8_t connectRetry = 0; - pClient = NimBLEDevice::createClient(); - pClient->setClientCallbacks(this); - #if !defined(CONFIG_IDF_TARGET_ESP32C5) - //DISABLE FOR ALL ESPS FOR NOW BASED ON ISSUES WITH C5 (2025-06-18) - //pClient->setConnectionParams(12,12,0,600,64,64); - #endif - #ifndef NUKI_USE_LATEST_NIMBLE - if (logger == nullptr) { - log_d("[%s] Connect timeout %d s", deviceName.c_str(), connectTimeoutSec); - } - else - { - logger->printf("[%s] Connect timeout %d s\r\n", deviceName.c_str(), connectTimeoutSec); - } - pClient->setConnectTimeout(connectTimeoutSec); - #else - if (logger == nullptr) { - log_d("[%s] Connect timeout %d ms", deviceName.c_str(), connectTimeoutSec * 1000); - } - else - { - logger->printf("[%s] Connect timeout %d ms\r\n", deviceName.c_str(), connectTimeoutSec * 1000); + while (connectRetry < connectRetries) { + if(!pClient->isConnected()) { + if (!pClient->connect(bleAddress, refreshServices)) { + if (debugNukiConnect) { + logMessageVar("[%s] Failed to connect", deviceName.c_str()); } - pClient->setConnectTimeout(connectTimeoutSec * 1000); + connectRetry++; + #ifndef NUKI_NO_WDT_RESET + esp_task_wdt_reset(); #endif - - delay(300); - - int loopCreateClient = 0; - - while(!pClient && loopCreateClient < 50) { - delay(100); - loopCreateClient++; - } - - if (!pClient) { - if (debugNukiConnect) { - logMessageVar("[%s] Failed to create client", deviceName.c_str()); - } - connectRetry++; - #ifndef NUKI_NO_WDT_RESET - esp_task_wdt_reset(); - #endif - delay(10); - continue; - } - } - - if(!pClient->isConnected()) { - if (!pClient->connect(bleAddress, refreshServices)) { - if (debugNukiConnect) { - logMessageVar("[%s] Failed to connect", deviceName.c_str()); - } - connectRetry++; - #ifndef NUKI_NO_WDT_RESET - esp_task_wdt_reset(); - #endif - delay(10); - continue; - } else { - refreshServices = false; - } + delay(50); + continue; + } else { + refreshServices = false; } + } - if (debugNukiConnect) { - if (logger == nullptr) { - log_d("[%s] Connected to: %s RSSI: %d", deviceName.c_str(), pClient->getPeerAddress().toString().c_str(), pClient->getRssi()); - } - else - { - logger->printf("[%s] Connected to: %s RSSI: %d\r\n", deviceName.c_str(), pClient->getPeerAddress().toString().c_str(), pClient->getRssi()); - } + if (debugNukiConnect) { + if (logger == nullptr) { + log_d("[%s] Connected to: %s RSSI: %d", deviceName.c_str(), pClient->getPeerAddress().toString().c_str(), pClient->getRssi()); } - - if(pairing) { - if (!registerOnGdioChar()) { - if (debugNukiConnect) { - logMessageVar("[%s] Failed to connect on registering GDIO", deviceName.c_str()); - } - connectRetry++; - #ifndef NUKI_NO_WDT_RESET - esp_task_wdt_reset(); - #endif - delay(10); - continue; - } - } else { - if (!registerOnUsdioChar()) { - if (debugNukiConnect) { - logMessageVar("[%s] Failed to connect on registering USDIO", deviceName.c_str()); - } - connectRetry++; - #ifndef NUKI_NO_WDT_RESET - esp_task_wdt_reset(); - #endif - delay(10); - continue; - } + else + { + logger->printf("[%s] Connected to: %s RSSI: %d\r\n", deviceName.c_str(), pClient->getPeerAddress().toString().c_str(), pClient->getRssi()); } - - bleScanner->enableScanning(true); - connecting = false; - return true; } - bleScanner->enableScanning(true); - connecting = false; - return false; - } - else - { - connecting = true; - bleScanner->enableScanning(false); - if (!pClient->isConnected()) { - if (debugNukiConnect) { - #if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)) - logMessageVar("connecting within: %s", pcTaskGetTaskName(xTaskGetCurrentTaskHandle())); - #else - logMessageVar("connecting within: %s", pcTaskGetName(xTaskGetCurrentTaskHandle())); + if(pairing) { + if (!registerOnGdioChar()) { + if (debugNukiConnect) { + logMessageVar("[%s] Failed to connect on registering GDIO", deviceName.c_str()); + } + connectRetry++; + #ifndef NUKI_NO_WDT_RESET + esp_task_wdt_reset(); #endif + delay(50); + continue; } - - uint8_t connectRetry = 0; - #ifdef NUKI_USE_LATEST_NIMBLE - pClient->setConnectTimeout(connectTimeoutSec * 1000); - #else - pClient->setConnectTimeout(connectTimeoutSec); - #endif - while (connectRetry < connectRetries) { + } else { + if (!registerOnUsdioChar()) { if (debugNukiConnect) { - logMessageVar("connection attempt %d", connectRetry); - } - if (pClient->connect(bleAddress, true)) { - if (pClient->isConnected() && registerOnGdioChar() && registerOnUsdioChar()) { //doublecheck if is connected otherwise registering gdio crashes esp - bleScanner->enableScanning(true); - connecting = false; - return true; - } else { - logMessage("BLE register on pairing or data Service/Char failed", 2); - } - } else { - pClient->disconnect(); - logMessageVar("BLE Connect failed, %d retries left", connectRetries - connectRetry - 1, 2); + logMessageVar("[%s] Failed to connect on registering USDIO", deviceName.c_str()); } connectRetry++; #ifndef NUKI_NO_WDT_RESET esp_task_wdt_reset(); #endif - delay(10); + delay(50); + continue; } - } else { - bleScanner->enableScanning(true); - connecting = false; - return true; } + bleScanner->enableScanning(true); connecting = false; - logMessage("BLE Connect failed", 2); - return false; + return true; } + + bleScanner->enableScanning(true); + connecting = false; + return false; } void NukiBle::updateConnectionState() { - if (connecting) { - if (altConnect) { - return; - } - lastStartTimeout = 0; + if (connecting || disconnecting) { + return; } #ifndef NUKI_64BIT_TIME @@ -476,32 +335,38 @@ void NukiBle::updateConnectionState() { if (debugNukiConnect) { logMessage("disconnecting BLE on timeout"); } - - if (altConnect) { - disconnect(); - } else { - pClient->disconnect(); - } - } + + disconnect(); + } } - + lastStartTimeout = 0; } } void NukiBle::disconnect() { - pClient = nullptr; + if (disconnecting) { + return; + } - #ifdef NUKI_USE_LATEST_NIMBLE - if(NimBLEDevice::getCreatedClientCount()) - #else - if(NimBLEDevice::getClientListSize()) - #endif - { - pClient = NimBLEDevice::getClientByPeerAddress(bleAddress); + disconnecting = true; + + if (pGdioCharacteristic != nullptr) { + pGdioCharacteristic->unsubscribe(false); } + pGdioCharacteristic = nullptr; + pKeyturnerPairingService = nullptr; + + if (pUsdioCharacteristic != nullptr) { + pUsdioCharacteristic->unsubscribe(false); + } + + pUsdioCharacteristic = nullptr; + pKeyturnerDataService = nullptr; + + if (pClient) { if (pClient->isConnected()) { if (debugNukiConnect) { @@ -520,7 +385,7 @@ void NukiBle::disconnect() delay(100); } - if (countDisconnects > 0 || pClient->isConnected()) + if (pClient->isConnected()) { if (debugNukiConnect) { logMessage("Error while disconnecting BLE client"); @@ -529,6 +394,8 @@ void NukiBle::disconnect() } } } + + disconnecting = false; } void NukiBle::setDisconnectTimeout(uint32_t timeoutMs) { @@ -729,9 +596,7 @@ Nuki::CmdResult NukiBle::retrieveKeypadEntries(const uint16_t offset, const uint if ((esp_timer_get_time() / 1000) - timeNow > GENERAL_TIMEOUT) { #endif logMessage("Receive keypad count timeout", 2); - if (altConnect) { - disconnect(); - } + disconnect(); return CmdResult::TimeOut; } delay(10); @@ -753,9 +618,7 @@ Nuki::CmdResult NukiBle::retrieveKeypadEntries(const uint16_t offset, const uint if ((esp_timer_get_time() / 1000) - timeNow > GENERAL_TIMEOUT) { #endif logMessage("Receive keypadcodes timeout", 2); - if (altConnect) { - disconnect(); - } + disconnect(); return CmdResult::TimeOut; } delay(10); @@ -796,9 +659,9 @@ Nuki::CmdResult NukiBle::genericCommand(Command command, bool withPin) { action.cmdType = Nuki::CommandType::CommandWithChallengeAndPin; } else { action.cmdType = Nuki::CommandType::CommandWithChallenge; - } + } action.command = command; - + Nuki::CmdResult result = executeAction(action); return result; } @@ -816,7 +679,7 @@ Nuki::CmdResult NukiBle::requestDailyStatistics() { action.command = Nuki::Command::RequestDailyStatistics; memcpy(action.payload, &payload, sizeof(payload)); action.payloadLen = sizeof(payload); - + Nuki::CmdResult result = executeAction(action); return result; } @@ -1158,38 +1021,26 @@ void NukiBle::saveCredentials() { } uint16_t NukiBle::getSecurityPincode() { - if (takeNukiBleSemaphore("retr pincode cred")) { - uint16_t storedPincode = 0000; - if ((preferences.getBytes(SECURITY_PINCODE_STORE_NAME, &storedPincode, 2) > 0)) { - giveNukiBleSemaphore(); - return storedPincode; - } - giveNukiBleSemaphore(); + uint16_t storedPincode = 0000; + if ((preferences.getBytes(SECURITY_PINCODE_STORE_NAME, &storedPincode, 2) > 0)) { + return storedPincode; } return 0; } uint32_t NukiBle::getUltraPincode() { - if (takeNukiBleSemaphore("retr pincode cred")) { - uint32_t storedPincode = 000000; - if ((preferences.getBytes(ULTRA_PINCODE_STORE_NAME, &storedPincode, 4) > 0)) { - giveNukiBleSemaphore(); - return storedPincode; - } - giveNukiBleSemaphore(); + uint32_t storedPincode = 000000; + if ((preferences.getBytes(ULTRA_PINCODE_STORE_NAME, &storedPincode, 4) > 0)) { + return storedPincode; } return 0; } void NukiBle::getMacAddress(char* macAddress) { unsigned char buf[6]; - if (takeNukiBleSemaphore("retr pincode cred")) { - if ((preferences.getBytes(BLE_ADDRESS_STORE_NAME, buf, 6) > 0)) { - BLEAddress address = BLEAddress(buf, 0); - sprintf(macAddress, "%d", address.toString().c_str()); - giveNukiBleSemaphore(); - } - giveNukiBleSemaphore(); + if ((preferences.getBytes(BLE_ADDRESS_STORE_NAME, buf, 6) > 0)) { + BLEAddress address = BLEAddress(buf, 0); + sprintf(macAddress, "%d", address.toString().c_str()); } } @@ -1197,64 +1048,56 @@ bool NukiBle::retrieveCredentials() { //TODO check on empty (invalid) credentials? unsigned char buff[6]; - if (takeNukiBleSemaphore("retr cred")) { - if ((preferences.getBytes(BLE_ADDRESS_STORE_NAME, buff, 6) > 0) - && (preferences.getBytes(SECRET_KEY_STORE_NAME, secretKeyK, 32) > 0) - && (preferences.getBytes(AUTH_ID_STORE_NAME, authorizationId, 4) > 0) - ) { - bleAddress = BLEAddress(buff, 0); - - if (debugNukiConnect) { - logMessageVar("[%s] Credentials retrieved :", deviceName.c_str()); - printBuffer(secretKeyK, sizeof(secretKeyK), false, SECRET_KEY_STORE_NAME, debugNukiHexData, logger); - logMessageVar("bleAddress: %s", bleAddress.toString().c_str()); - printBuffer(authorizationId, sizeof(authorizationId), false, AUTH_ID_STORE_NAME, debugNukiHexData, logger); - } + if ((preferences.getBytes(BLE_ADDRESS_STORE_NAME, buff, 6) > 0) + && (preferences.getBytes(SECRET_KEY_STORE_NAME, secretKeyK, 32) > 0) + && (preferences.getBytes(AUTH_ID_STORE_NAME, authorizationId, 4) > 0) + ) { + bleAddress = BLEAddress(buff, 0); - if (isCharArrayEmpty(secretKeyK, sizeof(secretKeyK)) || isCharArrayEmpty(authorizationId, sizeof(authorizationId))) { - logMessage("secret key OR authorizationId is empty: not paired", 2); - giveNukiBleSemaphore(); - return false; - } + if (debugNukiConnect) { + logMessageVar("[%s] Credentials retrieved :", deviceName.c_str()); + printBuffer(secretKeyK, sizeof(secretKeyK), false, SECRET_KEY_STORE_NAME, debugNukiHexData, logger); + logMessageVar("bleAddress: %s", bleAddress.toString().c_str()); + printBuffer(authorizationId, sizeof(authorizationId), false, AUTH_ID_STORE_NAME, debugNukiHexData, logger); + } - smartLockUltra = preferences.getBool(ULTRA_STORE_NAME, false); + if (isCharArrayEmpty(secretKeyK, sizeof(secretKeyK)) || isCharArrayEmpty(authorizationId, sizeof(authorizationId))) { + logMessage("secret key OR authorizationId is empty: not paired", 2); + return false; + } - if (isLockUltra()) { - preferences.getBytes(ULTRA_PINCODE_STORE_NAME, &ultraPinCode, 4); + smartLockUltra = preferences.getBool(ULTRA_STORE_NAME, false); - if (ultraPinCode == 0) { - logMessage("Pincode is 000000, probably not defined", 2); - } - } else { - preferences.getBytes(SECURITY_PINCODE_STORE_NAME, &pinCode, 2); + if (isLockUltra()) { + preferences.getBytes(ULTRA_PINCODE_STORE_NAME, &ultraPinCode, 4); - if (pinCode == 0) { - logMessage("Pincode is 000000, probably not defined", 2); - } + if (ultraPinCode == 0) { + logMessage("Pincode is 000000, probably not defined", 2); } - } else { - logMessage("Error getting data from NVS", 1); - giveNukiBleSemaphore(); - return false; + preferences.getBytes(SECURITY_PINCODE_STORE_NAME, &pinCode, 2); + + if (pinCode == 0) { + logMessage("Pincode is 000000, probably not defined", 2); + } } - giveNukiBleSemaphore(); + } else { + logMessage("Not paired", 1); + return false; } return true; } void NukiBle::deleteCredentials() { - if (takeNukiBleSemaphore("del cred")) { - unsigned char emptySecretKeyK[32] = {0x00}; - unsigned char emptyAuthorizationId[4] = {0x00}; - preferences.putBytes(SECRET_KEY_STORE_NAME, emptySecretKeyK, 32); - preferences.putBytes(AUTH_ID_STORE_NAME, emptyAuthorizationId, 4); - preferences.putBool(ULTRA_STORE_NAME, false); - // preferences.remove(SECRET_KEY_STORE_NAME); - // preferences.remove(AUTH_ID_STORE_NAME); - giveNukiBleSemaphore(); - } + unsigned char emptySecretKeyK[32] = {0x00}; + unsigned char emptyAuthorizationId[4] = {0x00}; + preferences.putBytes(SECRET_KEY_STORE_NAME, emptySecretKeyK, 32); + preferences.putBytes(AUTH_ID_STORE_NAME, emptyAuthorizationId, 4); + preferences.putBool(ULTRA_STORE_NAME, false); + // preferences.remove(SECRET_KEY_STORE_NAME); + // preferences.remove(AUTH_ID_STORE_NAME); + if (debugNukiConnect) { logMessage("Credentials deleted"); } @@ -1581,26 +1424,27 @@ bool NukiBle::sendPlainMessage(Command commandIdentifier, const unsigned char* p bool NukiBle::registerOnGdioChar() { // Obtain a reference to the KeyTurner Pairing service - if (isLockUltra()) { - pKeyturnerPairingService = pClient->getService(pairingServiceUltraUUID); - } else { - pKeyturnerPairingService = pClient->getService(pairingServiceUUID); - } - if (pKeyturnerPairingService != nullptr) { - //Obtain reference to GDIO char + if (pKeyturnerPairingService == nullptr) { if (isLockUltra()) { - pGdioCharacteristic = pKeyturnerPairingService->getCharacteristic(gdioUltraUUID); + pKeyturnerPairingService = pClient->getService(pairingServiceUltraUUID); } else { - pGdioCharacteristic = pKeyturnerPairingService->getCharacteristic(gdioUUID); + pKeyturnerPairingService = pClient->getService(pairingServiceUUID); + } + if (pKeyturnerPairingService != nullptr) { + if (pGdioCharacteristic == nullptr) { + //Obtain reference to GDIO char + if (isLockUltra()) { + pGdioCharacteristic = pKeyturnerPairingService->getCharacteristic(gdioUltraUUID); + } else { + pGdioCharacteristic = pKeyturnerPairingService->getCharacteristic(gdioUUID); + } + } } + } + + if (pKeyturnerPairingService != nullptr) { if (pGdioCharacteristic != nullptr) { if (pGdioCharacteristic->canIndicate()) { - using namespace std::placeholders; - #ifdef NUKI_USE_LATEST_NIMBLE - NimBLERemoteCharacteristic::notify_callback callback = std::bind(&NukiBle::notifyCallback, this, _1, _2, _3, _4); - #else - notify_callback callback = std::bind(&NukiBle::notifyCallback, this, _1, _2, _3, _4); - #endif if(!pGdioCharacteristic->subscribe(false, callback, true)) { logMessage("Unable to subscribe to GDIO characteristic", 2); refreshServices = true; @@ -1637,18 +1481,19 @@ bool NukiBle::registerOnGdioChar() { bool NukiBle::registerOnUsdioChar() { // Obtain a reference to the KeyTurner service - pKeyturnerDataService = pClient->getService(deviceServiceUUID); + if (pKeyturnerDataService == nullptr) { + pKeyturnerDataService = pClient->getService(deviceServiceUUID); + if (pKeyturnerDataService != nullptr) { + if (pUsdioCharacteristic == nullptr) { + //Obtain reference to GDIO char + pUsdioCharacteristic = pKeyturnerDataService->getCharacteristic(userDataUUID); + } + } + } + if (pKeyturnerDataService != nullptr) { - //Obtain reference to NDIO char - pUsdioCharacteristic = pKeyturnerDataService->getCharacteristic(userDataUUID); if (pUsdioCharacteristic != nullptr) { if (pUsdioCharacteristic->canIndicate()) { - using namespace std::placeholders; - #ifdef NUKI_USE_LATEST_NIMBLE - NimBLERemoteCharacteristic::notify_callback callback = std::bind(&NukiBle::notifyCallback, this, _1, _2, _3, _4); - #else - notify_callback callback = std::bind(&NukiBle::notifyCallback, this, _1, _2, _3, _4); - #endif if(!pUsdioCharacteristic->subscribe(false, callback, true)) { logMessage("Unable to subscribe to USDIO characteristic", 2); refreshServices = true; @@ -1685,6 +1530,8 @@ bool NukiBle::registerOnUsdioChar() { } void NukiBle::notifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* recData, size_t length, bool isNotify) { + delay(100); + #ifndef NUKI_64BIT_TIME lastHeartbeat = millis(); #else @@ -1699,6 +1546,7 @@ void NukiBle::notifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic, logger->printf("Notify callback for characteristic: %s of length: %d\r\n", pBLERemoteCharacteristic->getUUID().toString().c_str(), length); } } + printBuffer((byte*)recData, length, false, "Received data", debugNukiHexData, logger); if (pBLERemoteCharacteristic->getUUID() == gdioUUID || (pBLERemoteCharacteristic->getUUID() == gdioUltraUUID && (!recieveEncrypted || length < 24))) { @@ -1953,37 +1801,6 @@ const bool NukiBle::isLockUltra() const { return smartLockUltra; }; -bool NukiBle::takeNukiBleSemaphore(std::string taker) { - #ifndef NUKI_MUTEX_RECURSIVE - bool result = xSemaphoreTake(nukiBleSemaphore, NUKI_SEMAPHORE_TIMEOUT / portTICK_PERIOD_MS) == pdTRUE; - #else - bool result = xSemaphoreTakeRecursive(nukiBleSemaphore, NUKI_SEMAPHORE_TIMEOUT / portTICK_PERIOD_MS) == pdTRUE; - #endif - - if (!result) { - if (logger == nullptr) { - log_d("%s FAILED to take Nuki semaphore. Owner %s", taker.c_str(), owner.c_str()); - } - else - { - logger->printf("%s FAILED to take Nuki semaphore. Owner %s\r\n", taker.c_str(), owner.c_str()); - } - } else { - owner = taker; - } - - return result; -} - -void NukiBle::giveNukiBleSemaphore() { - owner = "free"; - #ifndef NUKI_MUTEX_RECURSIVE - xSemaphoreGive(nukiBleSemaphore); - #else - xSemaphoreGiveRecursive(nukiBleSemaphore); - #endif -} - int NukiBle::getRssi() const { return rssi; } diff --git a/src/NukiBle.h b/src/NukiBle.h index 63f108ad..a989cb32 100644 --- a/src/NukiBle.h +++ b/src/NukiBle.h @@ -24,7 +24,7 @@ #include "sodium/crypto_secretbox.h" #define GENERAL_TIMEOUT 3000 -#define CMD_TIMEOUT 10000 +#define CMD_TIMEOUT 3000 #define PAIRING_TIMEOUT 30000 #define HEARTBEAT_TIMEOUT 30000 @@ -457,17 +457,8 @@ class NukiBle : public BLEClientCallbacks, public BleScanner::Subscriber { Print* logger = nullptr; private: - #ifndef NUKI_MUTEX_RECURSIVE - SemaphoreHandle_t nukiBleSemaphore = xSemaphoreCreateMutex(); - #else - SemaphoreHandle_t nukiBleSemaphore = xSemaphoreCreateRecursiveMutex(); - #endif - bool takeNukiBleSemaphore(std::string taker); - std::string owner = "free"; - void giveNukiBleSemaphore(); - - bool altConnect = false; bool connecting = false; + bool disconnecting = false; bool statusUpdated = false; bool refreshServices = false; bool smartLockUltra = false; @@ -497,6 +488,12 @@ class NukiBle : public BLEClientCallbacks, public BleScanner::Subscriber { bool sendPlainMessage(Command commandIdentifier, const unsigned char* payload, const uint8_t payloadLen); bool sendEncryptedMessage(Command commandIdentifier, const unsigned char* payload, const uint8_t payloadLen); + #ifdef NUKI_USE_LATEST_NIMBLE + NimBLERemoteCharacteristic::notify_callback callback; + #else + notify_callback callback; + #endif + void notifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify); void saveCredentials(); bool retrieveCredentials(); @@ -513,17 +510,17 @@ class NukiBle : public BLEClientCallbacks, public BleScanner::Subscriber { uint32_t deviceId; //The ID of the Nuki App, Nuki Bridge or Nuki Fob to be authorized. BLEClient* pClient = nullptr; -//Keyturner Pairing Service + //Keyturner Pairing Service const NimBLEUUID pairingServiceUUID; -//Keyturner Pairing Service Ultra + //Keyturner Pairing Service Ultra const NimBLEUUID pairingServiceUltraUUID; -//Keyturner Service + //Keyturner Service const NimBLEUUID deviceServiceUUID; -//Keyturner pairing Data Input Output characteristic + //Keyturner pairing Data Input Output characteristic const NimBLEUUID gdioUUID; -//Keyturner pairing Data Input Output characteristic Ultra + //Keyturner pairing Data Input Output characteristic Ultra const NimBLEUUID gdioUltraUUID; -//User-Specific Data Input Output characteristic + //User-Specific Data Input Output characteristic const NimBLEUUID userDataUUID; const std::string preferencesId; diff --git a/src/NukiBle.hpp b/src/NukiBle.hpp index 8648987f..49cc70b3 100644 --- a/src/NukiBle.hpp +++ b/src/NukiBle.hpp @@ -4,70 +4,57 @@ namespace Nuki { template Nuki::CmdResult NukiBle::executeAction(const TDeviceAction action) { - if (!altConnect) { - #ifndef NUKI_64BIT_TIME - if (millis() - lastHeartbeat > HEARTBEAT_TIMEOUT) { - #else - if ((esp_timer_get_time() / 1000) - lastHeartbeat > HEARTBEAT_TIMEOUT) { - #endif - logMessage("Lock Heartbeat timeout, command failed", 1); - return Nuki::CmdResult::Error; - } - } - if (debugNukiConnect) { - logMessage("************************ CHECK PAIRED ************************"); - } - if (retrieveCredentials()) { + if(!isPairedWithLock()) { if (debugNukiConnect) { - logMessage("Credentials retrieved from preferences, ready for commands"); + logMessage("************************ CHECK PAIRED ************************"); } - } else { - if (debugNukiConnect) { - logMessage("Credentials NOT retrieved from preferences, first pair with the lock"); + if (retrieveCredentials()) { + if (debugNukiConnect) { + logMessage("Credentials retrieved from preferences, ready for commands"); + } + } else { + if (debugNukiConnect) { + logMessage("Credentials NOT retrieved from preferences, first pair with the lock"); + } + return Nuki::CmdResult::NotPaired; } - return Nuki::CmdResult::NotPaired; } - if (takeNukiBleSemaphore("exec Action")) { - if (debugNukiCommunication) { - logMessageVar("Start executing: %02x ", (unsigned int)action.command); - } + if (debugNukiCommunication) { + logMessageVar("Start executing: %02x ", (unsigned int)action.command); + } - while (1) { - extendDisconnectTimeout(); + while (1) { + extendDisconnectTimeout(); - Nuki::CmdResult result; - if (action.cmdType == Nuki::CommandType::Command) { - result = cmdStateMachine(action); - } - else if (action.cmdType == Nuki::CommandType::CommandWithChallenge) { - result = cmdChallStateMachine(action); - } - else if (action.cmdType == Nuki::CommandType::CommandWithChallengeAndAccept) { - result = cmdChallAccStateMachine(action); - } - else if (action.cmdType == Nuki::CommandType::CommandWithChallengeAndPin) { - result = cmdChallStateMachine(action, true); - } - else { - logMessage("Unknown cmd type", 2); - giveNukiBleSemaphore(); + Nuki::CmdResult result; + if (action.cmdType == Nuki::CommandType::Command) { + result = cmdStateMachine(action); + } + else if (action.cmdType == Nuki::CommandType::CommandWithChallenge) { + result = cmdChallStateMachine(action); + } + else if (action.cmdType == Nuki::CommandType::CommandWithChallengeAndAccept) { + result = cmdChallAccStateMachine(action); + } + else if (action.cmdType == Nuki::CommandType::CommandWithChallengeAndPin) { + result = cmdChallStateMachine(action, true); + } + else { + logMessage("Unknown cmd type", 2); + disconnect(); + return Nuki::CmdResult::Failed; + } + if (result != Nuki::CmdResult::Working) { + if (result == Nuki::CmdResult::Error || result == Nuki::CmdResult::Failed) { disconnect(); - return Nuki::CmdResult::Failed; - } - if (result != Nuki::CmdResult::Working) { - giveNukiBleSemaphore(); - - if (altConnect && (result == Nuki::CmdResult::Error || result == Nuki::CmdResult::Failed)) { - disconnect(); - } - return result; } - #ifndef NUKI_NO_WDT_RESET - esp_task_wdt_reset(); - #endif - delay(10); + return result; } + #ifndef NUKI_NO_WDT_RESET + esp_task_wdt_reset(); + #endif + delay(10); } return Nuki::CmdResult::Failed; } @@ -93,9 +80,7 @@ Nuki::CmdResult NukiBle::cmdStateMachine(const TDeviceAction action) { if (debugNukiCommunication) { logMessage("************************ SENDING COMMAND FAILED ************************"); } - if (altConnect) { - disconnect(); - } + disconnect(); nukiCommandState = CommandState::Idle; lastMsgCodeReceived = Command::Empty; return Nuki::CmdResult::Failed; @@ -109,9 +94,7 @@ Nuki::CmdResult NukiBle::cmdStateMachine(const TDeviceAction action) { if ((esp_timer_get_time() / 1000) - timeNow > CMD_TIMEOUT) { #endif logMessage("************************ COMMAND FAILED TIMEOUT************************", 2); - if (altConnect) { - disconnect(); - } + disconnect(); nukiCommandState = CommandState::Idle; return Nuki::CmdResult::TimeOut; } else if (lastMsgCodeReceived != Command::ErrorReport && lastMsgCodeReceived != Command::Empty) { @@ -125,9 +108,7 @@ Nuki::CmdResult NukiBle::cmdStateMachine(const TDeviceAction action) { if (debugNukiCommunication) { logMessage("************************ COMMAND FAILED ************************"); } - if (altConnect) { - disconnect(); - } + disconnect(); nukiCommandState = CommandState::Idle; lastMsgCodeReceived = Command::Empty; return Nuki::CmdResult::Failed; @@ -135,9 +116,7 @@ Nuki::CmdResult NukiBle::cmdStateMachine(const TDeviceAction action) { if (debugNukiCommunication) { logMessage("************************ COMMAND FAILED LOCK BUSY ************************"); } - if (altConnect) { - disconnect(); - } + disconnect(); nukiCommandState = CommandState::Idle; lastMsgCodeReceived = Command::Empty; return Nuki::CmdResult::Lock_Busy; @@ -146,9 +125,7 @@ Nuki::CmdResult NukiBle::cmdStateMachine(const TDeviceAction action) { break; default: { logMessage("Unknown request command state", 2); - if (altConnect) { - disconnect(); - } + disconnect(); return Nuki::CmdResult::Failed; break; } @@ -178,9 +155,7 @@ Nuki::CmdResult NukiBle::cmdChallStateMachine(const TDeviceAction action, const if (debugNukiCommunication) { logMessage("************************ SENDING CHALLENGE FAILED ************************"); } - if (altConnect) { - disconnect(); - } + disconnect(); nukiCommandState = CommandState::Idle; lastMsgCodeReceived = Command::Empty; return Nuki::CmdResult::Failed; @@ -197,9 +172,7 @@ Nuki::CmdResult NukiBle::cmdChallStateMachine(const TDeviceAction action, const if ((esp_timer_get_time() / 1000) - timeNow > CMD_TIMEOUT) { #endif logMessage("************************ COMMAND FAILED TIMEOUT ************************", 2); - if (altConnect) { - disconnect(); - } + disconnect(); nukiCommandState = CommandState::Idle; return Nuki::CmdResult::TimeOut; } else if (lastMsgCodeReceived == Command::Challenge) { @@ -245,9 +218,7 @@ Nuki::CmdResult NukiBle::cmdChallStateMachine(const TDeviceAction action, const if (debugNukiCommunication) { logMessage("************************ SENDING COMMAND FAILED ************************"); } - if (altConnect) { - disconnect(); - } + disconnect(); nukiCommandState = CommandState::Idle; lastMsgCodeReceived = Command::Empty; return Nuki::CmdResult::Failed; @@ -264,18 +235,14 @@ Nuki::CmdResult NukiBle::cmdChallStateMachine(const TDeviceAction action, const if ((esp_timer_get_time() / 1000) - timeNow > CMD_TIMEOUT) { #endif logMessage("************************ COMMAND FAILED TIMEOUT ************************", 2); - if (altConnect) { - disconnect(); - } + disconnect(); nukiCommandState = CommandState::Idle; return Nuki::CmdResult::TimeOut; } else if (lastMsgCodeReceived == Command::ErrorReport && errorCode != 69) { if (debugNukiCommunication) { logMessage("************************ COMMAND FAILED ************************"); } - if (altConnect) { - disconnect(); - } + disconnect(); nukiCommandState = CommandState::Idle; lastMsgCodeReceived = Command::Empty; return Nuki::CmdResult::Failed; @@ -283,9 +250,7 @@ Nuki::CmdResult NukiBle::cmdChallStateMachine(const TDeviceAction action, const if (debugNukiCommunication) { logMessage("************************ COMMAND FAILED LOCK BUSY ************************"); } - if (altConnect) { - disconnect(); - } + disconnect(); nukiCommandState = CommandState::Idle; lastMsgCodeReceived = Command::Empty; return Nuki::CmdResult::Lock_Busy; @@ -300,9 +265,7 @@ Nuki::CmdResult NukiBle::cmdChallStateMachine(const TDeviceAction action, const } default: logMessage("Unknown request command state", 2); - if (altConnect) { - disconnect(); - } + disconnect(); return Nuki::CmdResult::Failed; break; } @@ -331,9 +294,7 @@ Nuki::CmdResult NukiBle::cmdChallAccStateMachine(const TDeviceAction action) { if (debugNukiCommunication) { logMessage("************************ SENDING CHALLENGE FAILED ************************"); } - if (altConnect) { - disconnect(); - } + disconnect(); nukiCommandState = CommandState::Idle; lastMsgCodeReceived = Command::Empty; return Nuki::CmdResult::Failed; @@ -350,9 +311,7 @@ Nuki::CmdResult NukiBle::cmdChallAccStateMachine(const TDeviceAction action) { if ((esp_timer_get_time() / 1000) - timeNow > CMD_TIMEOUT) { #endif logMessage("************************ COMMAND FAILED TIMEOUT ************************", 2); - if (altConnect) { - disconnect(); - } + disconnect(); nukiCommandState = CommandState::Idle; return Nuki::CmdResult::TimeOut; } else if (lastMsgCodeReceived == Command::Challenge) { @@ -383,9 +342,7 @@ Nuki::CmdResult NukiBle::cmdChallAccStateMachine(const TDeviceAction action) { if (debugNukiCommunication) { logMessage("************************ SENDING COMMAND FAILED ************************"); } - if (altConnect) { - disconnect(); - } + disconnect(); nukiCommandState = CommandState::Idle; lastMsgCodeReceived = Command::Empty; return Nuki::CmdResult::Failed; @@ -402,9 +359,7 @@ Nuki::CmdResult NukiBle::cmdChallAccStateMachine(const TDeviceAction action) { if ((esp_timer_get_time() / 1000) - timeNow > CMD_TIMEOUT) { #endif logMessage("************************ ACCEPT FAILED TIMEOUT ************************", 2); - if (altConnect) { - disconnect(); - } + disconnect(); nukiCommandState = CommandState::Idle; return Nuki::CmdResult::TimeOut; } else if (lastMsgCodeReceived == Command::Status && (CommandStatus)receivedStatus == CommandStatus::Accepted) { @@ -436,18 +391,14 @@ Nuki::CmdResult NukiBle::cmdChallAccStateMachine(const TDeviceAction action) { if ((esp_timer_get_time() / 1000) - timeNow > CMD_TIMEOUT) { #endif logMessage("************************ COMMAND FAILED TIMEOUT ************************", 2); - if (altConnect) { - disconnect(); - } + disconnect(); nukiCommandState = CommandState::Idle; return Nuki::CmdResult::TimeOut; } else if (lastMsgCodeReceived == Command::ErrorReport && errorCode != 69) { if (debugNukiCommunication) { logMessage("************************ COMMAND FAILED ************************"); } - if (altConnect) { - disconnect(); - } + disconnect(); nukiCommandState = CommandState::Idle; lastMsgCodeReceived = Command::Empty; return Nuki::CmdResult::Failed; @@ -455,9 +406,7 @@ Nuki::CmdResult NukiBle::cmdChallAccStateMachine(const TDeviceAction action) { if (debugNukiCommunication) { logMessage("************************ COMMAND FAILED LOCK BUSY ************************"); } - if (altConnect) { - disconnect(); - } + disconnect(); nukiCommandState = CommandState::Idle; lastMsgCodeReceived = Command::Empty; return Nuki::CmdResult::Lock_Busy; @@ -473,9 +422,7 @@ Nuki::CmdResult NukiBle::cmdChallAccStateMachine(const TDeviceAction action) { } default: logMessage("Unknown request command state", 2); - if (altConnect) { - disconnect(); - } + disconnect(); return Nuki::CmdResult::Failed; break; }