From a12a166734d30700c8c5b742953f05fb676eac7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Ole=20Sch=C3=BCmann?= Date: Thu, 2 Oct 2025 21:25:04 +0700 Subject: [PATCH] add GPIO output for bluetooth communication error (#701) --- src/Gpio.cpp | 5 ++++- src/Gpio.h | 2 ++ src/NukiOpenerWrapper.cpp | 13 +++++++++++++ src/NukiOpenerWrapper.h | 7 ++++++- src/NukiWrapper.cpp | 13 +++++++++++++ src/NukiWrapper.h | 5 +++++ 6 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/Gpio.cpp b/src/Gpio.cpp index 26f24f4..deca13b 100644 --- a/src/Gpio.cpp +++ b/src/Gpio.cpp @@ -180,6 +180,7 @@ void Gpio::setPins() case PinRole::GeneralOutput: case PinRole::OutputHighMqttConnected: case PinRole::OutputHighNetworkConnected: + case PinRole::OutputHighBluetoothCommError: pinMode(entry.pin, OUTPUT); break; case PinRole::Ethernet: @@ -503,12 +504,13 @@ String Gpio::getRoleDescription(const PinRole& role) const return "Output: High when MQTT connected"; case PinRole::OutputHighNetworkConnected: return "Output: High when network connected"; + case PinRole::OutputHighBluetoothCommError: + return "Output: High on bluetooth communication error"; default: return "Unknown"; } } - GpioAction Gpio::getGpioAction(const PinRole &role) const { switch(role) @@ -552,6 +554,7 @@ GpioAction Gpio::getGpioAction(const PinRole &role) const case PinRole::OutputHighRtoOrCmActive: case PinRole::OutputHighMqttConnected: case PinRole::OutputHighNetworkConnected: + case PinRole::OutputHighBluetoothCommError: default: return GpioAction::None; } diff --git a/src/Gpio.h b/src/Gpio.h index f910200..513b1ca 100644 --- a/src/Gpio.h +++ b/src/Gpio.h @@ -31,6 +31,7 @@ enum class PinRole Ethernet, OutputHighMqttConnected, OutputHighNetworkConnected, + OutputHighBluetoothCommError }; enum class GpioAction @@ -127,6 +128,7 @@ private: PinRole::InputDeactivateCM, PinRole::OutputHighMqttConnected, PinRole::OutputHighNetworkConnected, + PinRole::OutputHighBluetoothCommError, PinRole::OutputHighLocked, PinRole::OutputHighUnlocked, PinRole::OutputHighRtoActive, diff --git a/src/NukiOpenerWrapper.cpp b/src/NukiOpenerWrapper.cpp index 3ec5012..3fa75c5 100644 --- a/src/NukiOpenerWrapper.cpp +++ b/src/NukiOpenerWrapper.cpp @@ -46,6 +46,9 @@ NukiOpenerWrapper::NukiOpenerWrapper(const std::string& deviceName, NukiDeviceId network->setAuthCommandReceivedCallback(nukiOpenerInst->onAuthCommandReceivedCallback); _gpio->addCallback(NukiOpenerWrapper::gpioActionCallback); +#ifndef NUKI_HUB_UPDATER + _pinsCommError = _gpio->getPinsWithRole(PinRole::OutputHighBluetoothCommError); +#endif } @@ -299,6 +302,7 @@ void NukiOpenerWrapper::update() if(cmdResult != Nuki::CmdResult::Success) { + setCommErrorPins(HIGH); Log->print("Opener: Last command failed, retrying after "); Log->print(_retryDelay); Log->print(" milliseconds. Retry "); @@ -318,6 +322,7 @@ void NukiOpenerWrapper::update() } postponeBleWatchdog(); } + setCommErrorPins(LOW); if(cmdResult == Nuki::CmdResult::Success) { @@ -3746,6 +3751,14 @@ const std::string NukiOpenerWrapper::hardwareVersion() const return _hardwareVersion; } +void NukiOpenerWrapper::setCommErrorPins(const uint8_t& value) +{ + for (uint8_t pin : _pinsCommError) + { + _gpio->setPinOutput(pin, value); + } +} + void NukiOpenerWrapper::disableWatchdog() { _restartBeaconTimeout = -1; diff --git a/src/NukiOpenerWrapper.h b/src/NukiOpenerWrapper.h index 9d02932..988b2ce 100644 --- a/src/NukiOpenerWrapper.h +++ b/src/NukiOpenerWrapper.h @@ -42,6 +42,8 @@ public: const std::string firmwareVersion() const; const std::string hardwareVersion() const; + void setCommErrorPins(const uint8_t& value); + const BleScanner::Scanner* bleScanner(); void notify(NukiOpener::EventType eventType) override; @@ -81,8 +83,11 @@ private: NukiOpener::NukiOpener _nukiOpener; BleScanner::Scanner* _bleScanner = nullptr; NukiNetworkOpener* _network = nullptr; - Gpio* _gpio = nullptr; Preferences* _preferences = nullptr; + Gpio* _gpio = nullptr; + + std::vector _pinsCommError; + int _intervalLockstate = 0; // seconds int _intervalBattery = 0; // seconds int _intervalConfig = 60 * 60; // seconds diff --git a/src/NukiWrapper.cpp b/src/NukiWrapper.cpp index ac61e6e..e56944f 100644 --- a/src/NukiWrapper.cpp +++ b/src/NukiWrapper.cpp @@ -46,6 +46,9 @@ NukiWrapper::NukiWrapper(const std::string& deviceName, NukiDeviceId* deviceId, network->setAuthCommandReceivedCallback(nukiInst->onAuthCommandReceivedCallback); _gpio->addCallback(NukiWrapper::gpioActionCallback); +#ifndef NUKI_HUB_UPDATER + _pinsCommError = _gpio->getPinsWithRole(PinRole::OutputHighBluetoothCommError); +#endif } @@ -318,6 +321,7 @@ void NukiWrapper::update(bool reboot) if(cmdResult != Nuki::CmdResult::Success) { + setCommErrorPins(HIGH); Log->print("Lock: Last command failed, retrying after "); Log->print(_retryDelay); Log->print(" milliseconds. Retry "); @@ -337,6 +341,7 @@ void NukiWrapper::update(bool reboot) } postponeBleWatchdog(); } + setCommErrorPins(LOW); if(cmdResult == Nuki::CmdResult::Success) { @@ -4153,6 +4158,14 @@ const std::string NukiWrapper::hardwareVersion() const return _hardwareVersion; } +void NukiWrapper::setCommErrorPins(const uint8_t& value) +{ + for (uint8_t pin : _pinsCommError) + { + _gpio->setPinOutput(pin, value); + } +} + void NukiWrapper::disableWatchdog() { _restartBeaconTimeout = -1; diff --git a/src/NukiWrapper.h b/src/NukiWrapper.h index b51201b..3163c27 100644 --- a/src/NukiWrapper.h +++ b/src/NukiWrapper.h @@ -48,6 +48,8 @@ public: const std::string firmwareVersion() const; const std::string hardwareVersion() const; + void setCommErrorPins(const uint8_t& value); + void notify(Nuki::EventType eventType) override; private: @@ -91,6 +93,9 @@ private: NukiNetworkLock* _network = nullptr; NukiOfficial* _nukiOfficial = nullptr; Gpio* _gpio = nullptr; + + std::vector _pinsCommError; + Preferences* _preferences; int _intervalLockstate = 0; // seconds int _intervalHybridLockstate = 0; // seconds