diff --git a/Gpio.cpp b/Gpio.cpp index af70ce7..7917cdd 100644 --- a/Gpio.cpp +++ b/Gpio.cpp @@ -43,6 +43,22 @@ void Gpio::init() pinMode(entry.pin, INPUT_PULLUP); attachInterrupt(entry.pin, isrUnlatch, FALLING); break; + case PinRole::InputElectricStrikeActuation: + pinMode(entry.pin, INPUT_PULLUP); + attachInterrupt(entry.pin, isrElectricStrikeActuation, FALLING); + break; + case PinRole::InputActivateRTO: + pinMode(entry.pin, INPUT_PULLUP); + attachInterrupt(entry.pin, isrActivateRTO, FALLING); + break; + case PinRole::InputActivateCM: + pinMode(entry.pin, INPUT_PULLUP); + attachInterrupt(entry.pin, isrActivateCM, FALLING); + break; + case PinRole::InputDeactivateRtoCm: + pinMode(entry.pin, INPUT_PULLUP); + attachInterrupt(entry.pin, isrDeactivateRtoCm, FALLING); + break; default: pinMode(entry.pin, OUTPUT); break; @@ -115,19 +131,6 @@ const std::vector &Gpio::pinConfiguration() const return _pinConfiguration; } -PinRole Gpio::getPinRole(uint8_t pin) -{ - for(const auto& entry : _pinConfiguration) - { - if(entry.pin == pin) - { - return entry.role; - } - } - - return PinRole::Disabled; -} - String Gpio::getRoleDescription(PinRole role) const { switch(role) @@ -140,6 +143,14 @@ String Gpio::getRoleDescription(PinRole role) const return "Input: Unlock"; case PinRole::InputUnlatch: return "Input: Unlatch"; + case PinRole::InputElectricStrikeActuation: + return "Input: Electric strike actuation"; + case PinRole::InputActivateRTO: + return "Input: Activate RTO"; + case PinRole::InputActivateCM: + return "Input: Activate CM"; + case PinRole::InputDeactivateRtoCm: + return "Input: Deactivate RTO/CM"; case PinRole::OutputHighLocked: return "Output: High when locked"; case PinRole::OutputHighUnlocked: @@ -211,6 +222,34 @@ void Gpio::isrUnlatch() _debounceTs = millis() + _debounceTime; } +void Gpio::isrElectricStrikeActuation() +{ + if(millis() < _debounceTs) return; + _inst->notify(GpioAction::ElectricStrikeActuation); + _debounceTs = millis() + _debounceTime; +} + +void Gpio::isrActivateRTO() +{ + if(millis() < _debounceTs) return; + _inst->notify(GpioAction::ActivateRTO); + _debounceTs = millis() + _debounceTime; +} + +void Gpio::isrActivateCM() +{ + if(millis() < _debounceTs) return; + _inst->notify(GpioAction::ActivateCM); + _debounceTs = millis() + _debounceTime; +} + +void Gpio::isrDeactivateRtoCm() +{ + if(millis() < _debounceTs) return; + _inst->notify(GpioAction::DeactivateRtoCm); + _debounceTs = millis() + _debounceTime; +} + void Gpio::setPinOutput(const uint8_t& pin, const uint8_t& state) { digitalWrite(pin, state); diff --git a/Gpio.h b/Gpio.h index 242849e..dd1246f 100644 --- a/Gpio.h +++ b/Gpio.h @@ -10,6 +10,10 @@ enum class PinRole InputLock, InputUnlock, InputUnlatch, + InputElectricStrikeActuation, + InputActivateRTO, + InputActivateCM, + InputDeactivateRtoCm, OutputHighLocked, OutputHighUnlocked, OutputHighMotorBlocked, @@ -19,7 +23,11 @@ enum class GpioAction { Lock, Unlock, - Unlatch + Unlatch, + ElectricStrikeActuation, + ActivateRTO, + ActivateCM, + DeactivateRtoCm }; struct PinEntry @@ -42,7 +50,6 @@ public: const std::vector& availablePins() const; const std::vector& pinConfiguration() const; - PinRole getPinRole(uint8_t pin); String getRoleDescription(PinRole role) const; void getConfigurationText(String& text, const std::vector& pinConfiguration) const; @@ -60,6 +67,10 @@ private: PinRole::InputLock, PinRole::InputUnlock, PinRole::InputUnlatch, + PinRole::InputElectricStrikeActuation, + PinRole::InputActivateRTO, + PinRole::InputActivateCM, + PinRole::InputDeactivateRtoCm, PinRole::OutputHighLocked, PinRole::OutputHighUnlocked }; @@ -70,6 +81,10 @@ private: static void IRAM_ATTR isrLock(); static void IRAM_ATTR isrUnlock(); static void IRAM_ATTR isrUnlatch(); + static void IRAM_ATTR isrElectricStrikeActuation(); + static void IRAM_ATTR isrActivateRTO(); + static void IRAM_ATTR isrActivateCM(); + static void IRAM_ATTR isrDeactivateRtoCm(); std::vector> _callbacks; diff --git a/NukiOpenerWrapper.cpp b/NukiOpenerWrapper.cpp index cc33c25..3fa37a0 100644 --- a/NukiOpenerWrapper.cpp +++ b/NukiOpenerWrapper.cpp @@ -8,11 +8,12 @@ NukiOpenerWrapper* nukiOpenerInst; -NukiOpenerWrapper::NukiOpenerWrapper(const std::string& deviceName, uint32_t id, BleScanner::Scanner* scanner, NetworkOpener* network, Preferences* preferences) +NukiOpenerWrapper::NukiOpenerWrapper(const std::string& deviceName, uint32_t id, BleScanner::Scanner* scanner, NetworkOpener* network, Gpio* gpio, Preferences* preferences) : _deviceName(deviceName), _nukiOpener(deviceName, id), _bleScanner(scanner), _network(network), + _gpio(gpio), _preferences(preferences) { nukiOpenerInst = this; @@ -26,6 +27,8 @@ NukiOpenerWrapper::NukiOpenerWrapper(const std::string& deviceName, uint32_t id, network->setLockActionReceivedCallback(nukiOpenerInst->onLockActionReceivedCallback); network->setConfigUpdateReceivedCallback(nukiOpenerInst->onConfigUpdateReceivedCallback); network->setKeypadCommandReceivedCallback(nukiOpenerInst->onKeypadCommandReceivedCallback); + + _gpio->addCallback(NukiOpenerWrapper::gpioActionCallback); } @@ -252,6 +255,36 @@ void NukiOpenerWrapper::update() memcpy(&_lastKeyTurnerState, &_keyTurnerState, sizeof(NukiOpener::OpenerState)); } + +void NukiOpenerWrapper::electricStrikeActuation() +{ + _nextLockAction = NukiOpener::LockAction::ElectricStrikeActuation; +} + +void NukiOpenerWrapper::activateRTO() +{ + _nextLockAction = NukiOpener::LockAction::ActivateRTO; +} + +void NukiOpenerWrapper::activateCM() +{ + _nextLockAction = NukiOpener::LockAction::ActivateCM; +} + +void NukiOpenerWrapper::deactivateRtoCm() +{ + if(_keyTurnerState.nukiState == NukiOpener::State::ContinuousMode) + { + _nextLockAction = NukiOpener::LockAction::DeactivateCM; + return; + } + + if(_keyTurnerState.lockState == NukiOpener::LockState::RTOactive) + { + _nextLockAction = NukiOpener::LockAction::DeactivateRTO; + } +} + bool NukiOpenerWrapper::isPinSet() { return _nukiOpener.getSecurityPincode() != 0; @@ -448,6 +481,25 @@ void NukiOpenerWrapper::onKeypadCommandReceivedCallback(const char *command, con nukiOpenerInst->onKeypadCommandReceived(command, id, name, code, enabled); } +void NukiOpenerWrapper::gpioActionCallback(const GpioAction &action) +{ + switch(action) + { + case GpioAction::ElectricStrikeActuation: + nukiOpenerInst->electricStrikeActuation(); + break; + case GpioAction::ActivateRTO: + nukiOpenerInst->activateRTO(); + break; + case GpioAction::ActivateCM: + nukiOpenerInst->activateCM(); + break; + case GpioAction::DeactivateRtoCm: + nukiOpenerInst->deactivateRtoCm(); + break; + } +} + void NukiOpenerWrapper::onConfigUpdateReceived(const char *topic, const char *value) { if(strcmp(topic, mqtt_topic_config_button_enabled) == 0) diff --git a/NukiOpenerWrapper.h b/NukiOpenerWrapper.h index 01a903a..fe8b681 100644 --- a/NukiOpenerWrapper.h +++ b/NukiOpenerWrapper.h @@ -5,16 +5,22 @@ #include "NukiOpenerConstants.h" #include "NukiDataTypes.h" #include "BleScanner.h" +#include "Gpio.h" class NukiOpenerWrapper : public NukiOpener::SmartlockEventHandler { public: - NukiOpenerWrapper(const std::string& deviceName, uint32_t id, BleScanner::Scanner* scanner, NetworkOpener* network, Preferences* preferences); + NukiOpenerWrapper(const std::string& deviceName, uint32_t id, BleScanner::Scanner* scanner, NetworkOpener* network, Gpio* gpio, Preferences* preferences); virtual ~NukiOpenerWrapper(); void initialize(); void update(); + void electricStrikeActuation(); + void activateRTO(); + void activateCM(); + void deactivateRtoCm(); + bool isPinSet(); void setPin(const uint16_t pin); @@ -40,6 +46,7 @@ private: static bool onLockActionReceivedCallback(const char* value); static void onConfigUpdateReceivedCallback(const char* topic, const char* value); static void onKeypadCommandReceivedCallback(const char* command, const uint& id, const String& name, const String& code, const int& enabled); + static void gpioActionCallback(const GpioAction& action); void onConfigUpdateReceived(const char* topic, const char* value); void onKeypadCommandReceived(const char* command, const uint& id, const String& name, const String& code, const int& enabled); @@ -61,9 +68,10 @@ private: std::string _deviceName; NukiOpener::NukiOpener _nukiOpener; - BleScanner::Scanner* _bleScanner; - NetworkOpener* _network; - Preferences* _preferences; + BleScanner::Scanner* _bleScanner = nullptr; + NetworkOpener* _network = nullptr; + Gpio* _gpio = nullptr; + Preferences* _preferences = nullptr; int _intervalLockstate = 0; // seconds int _intervalBattery = 0; // seconds int _intervalConfig = 60 * 60; // seconds diff --git a/WebCfgServer.cpp b/WebCfgServer.cpp index 20a1835..9b96f41 100644 --- a/WebCfgServer.cpp +++ b/WebCfgServer.cpp @@ -36,13 +36,13 @@ WebCfgServer::WebCfgServer(NukiWrapper* nuki, NukiOpenerWrapper* nukiOpener, Net _pinsConfigured = true; - if(_nuki != nullptr) + if(_nuki != nullptr && !_nuki->isPinSet()) { - _pinsConfigured = _pinsConfigured && _nuki->isPinSet(); + _pinsConfigured = false; } - if(_nukiOpener != nullptr) + if(_nukiOpener != nullptr && !_nukiOpener->isPinSet()) { - _pinsConfigured = _pinsConfigured && _nukiOpener->isPinSet(); + _pinsConfigured = false; } _brokerConfigured = _preferences->getString(preference_mqtt_broker).length() > 0 && _preferences->getInt(preference_mqtt_broker_port) > 0; diff --git a/main.cpp b/main.cpp index a5f2ab2..15357b7 100644 --- a/main.cpp +++ b/main.cpp @@ -230,7 +230,7 @@ void setup() Log->println(openerEnabled ? F("NUKI Opener enabled") : F("NUKI Opener disabled")); if(openerEnabled) { - nukiOpener = new NukiOpenerWrapper("NukiHub", deviceId, bleScanner, networkOpener, preferences); + nukiOpener = new NukiOpenerWrapper("NukiHub", deviceId, bleScanner, networkOpener, gpio, preferences); nukiOpener->initialize(); }