diff --git a/CMakeLists.txt b/CMakeLists.txt index b7204b3..8223f4b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,7 @@ file(GLOB SRCFILES PresenceDetection.cpp PreferencesKeys.h SpiffsCookie.cpp + Gpio.cpp Version.h include/RTOS.h lib/ESP32_BLE_Arduino-1.0.1/src/*.cpp diff --git a/Gpio.cpp b/Gpio.cpp new file mode 100644 index 0000000..69c3c98 --- /dev/null +++ b/Gpio.cpp @@ -0,0 +1,46 @@ +#include +#include "Gpio.h" +#include "Arduino.h" +#include "Pins.h" + +Gpio* Gpio::_inst = nullptr; +NukiWrapper* Gpio::_nuki = nullptr; +unsigned long Gpio::_lockedTs = 0; +const uint Gpio::_debounceTime = 1000; + +void Gpio::init(NukiWrapper* nuki) +{ + _nuki = nuki; + + pinMode(TRIGGER_LOCK_PIN, INPUT_PULLUP); + pinMode(TRIGGER_UNLOCK_PIN, INPUT_PULLUP); + pinMode(TRIGGER_UNLATCH_PIN, INPUT_PULLUP); + + attachInterrupt(TRIGGER_LOCK_PIN, isrLock, FALLING); + attachInterrupt(TRIGGER_UNLOCK_PIN, isrUnlock, FALLING); + attachInterrupt(TRIGGER_UNLATCH_PIN, isrUnlatch, FALLING); +} + +void Gpio::isrLock() +{ + if(millis() < _lockedTs) return; + _nuki->lock(); + _lockedTs = millis() + _debounceTime; + Serial.println(F("Lock via GPIO"));; +} + +void Gpio::isrUnlock() +{ + if(millis() < _lockedTs) return; + _nuki->unlock(); + _lockedTs = millis() + _debounceTime; + Serial.println(F("Unlock via GPIO"));; +} + +void Gpio::isrUnlatch() +{ + if(millis() < _lockedTs) return; + _nuki->unlatch(); + _lockedTs = millis() + _debounceTime; + Serial.println(F("Unlatch via GPIO"));; +} diff --git a/Gpio.h b/Gpio.h new file mode 100644 index 0000000..6d4383e --- /dev/null +++ b/Gpio.h @@ -0,0 +1,22 @@ +#pragma once + + +#include "NukiWrapper.h" + +class Gpio +{ +public: + Gpio() = delete; + static void init(NukiWrapper* nuki); + +private: + static const uint _debounceTime; + + static void IRAM_ATTR isrLock(); + static void IRAM_ATTR isrUnlock(); + static void IRAM_ATTR isrUnlatch(); + + static Gpio* _inst; + static NukiWrapper* _nuki; + static unsigned long _lockedTs; +}; diff --git a/NukiWrapper.cpp b/NukiWrapper.cpp index bc74cfa..9836a28 100644 --- a/NukiWrapper.cpp +++ b/NukiWrapper.cpp @@ -134,6 +134,21 @@ void NukiWrapper::update() memcpy(&_lastKeyTurnerState, &_keyTurnerState, sizeof(NukiLock::KeyTurnerState)); } +void NukiWrapper::lock() +{ + _nextLockAction = NukiLock::LockAction::Lock; +} + +void NukiWrapper::unlock() +{ + _nextLockAction = NukiLock::LockAction::Unlock; +} + +void NukiWrapper::unlatch() +{ + _nextLockAction = NukiLock::LockAction::Unlatch; +} + void NukiWrapper::setPin(const uint16_t pin) { _nukiLock.saveSecurityPincode(pin); diff --git a/NukiWrapper.h b/NukiWrapper.h index 00155d4..6e809df 100644 --- a/NukiWrapper.h +++ b/NukiWrapper.h @@ -15,8 +15,11 @@ public: void initialize(); void update(); - void setPin(const uint16_t pin); + void lock(); + void unlock(); + void unlatch(); + void setPin(const uint16_t pin); void unpair(); void disableHASS(); diff --git a/Pins.h b/Pins.h index df5d0c3..bfe2ec3 100644 --- a/Pins.h +++ b/Pins.h @@ -3,3 +3,6 @@ #define NETWORK_SELECT 26 #define ETHERNET_CS_PIN 5 #define ETHERNET_RESET_PIN 33 +#define TRIGGER_LOCK_PIN 32 +#define TRIGGER_UNLOCK_PIN 33 +#define TRIGGER_UNLATCH_PIN 27 diff --git a/PreferencesKeys.h b/PreferencesKeys.h index aa3d331..ea2ff8a 100644 --- a/PreferencesKeys.h +++ b/PreferencesKeys.h @@ -22,6 +22,7 @@ #define preference_cred_user "crdusr" #define preference_cred_password "crdpass" #define preference_publish_authdata "pubauth" +#define preference_gpio_locking_enabled "gpiolck" #define preference_presence_detection_timeout "prdtimeout" #define preference_has_mac_saved "hasmac" #define preference_has_mac_byte_0 "macb0" diff --git a/Version.h b/Version.h index 9530754..bcebc7b 100644 --- a/Version.h +++ b/Version.h @@ -1,3 +1,3 @@ #pragma once -#define nuki_hub_version "4.6" \ No newline at end of file +#define nuki_hub_version "4.7" \ No newline at end of file diff --git a/WebCfgServer.cpp b/WebCfgServer.cpp index e097b14..43736ac 100644 --- a/WebCfgServer.cpp +++ b/WebCfgServer.cpp @@ -274,6 +274,11 @@ bool WebCfgServer::processArgs(String& message) _preferences->putBool(preference_publish_authdata, (value == "1")); configChanged = true; } + else if(key == "GPLCK") + { + _preferences->putBool(preference_gpio_locking_enabled, (value == "1")); + configChanged = true; + } else if(key == "LOCKENA") { _preferences->putBool(preference_lock_enabled, (value == "1")); @@ -544,6 +549,7 @@ void WebCfgServer::buildNukiConfigHtml(String &response) printInputField(response, "LSTINT", "Query interval lock state (seconds)", _preferences->getInt(preference_query_interval_lockstate), 10); printInputField(response, "BATINT", "Query interval battery (seconds)", _preferences->getInt(preference_query_interval_battery), 10); printCheckBox(response, "PUBAUTH", "Publish auth data (May reduce battery life)", _preferences->getBool(preference_publish_authdata)); + printCheckBox(response, "GPLCK", "Enable control via GPIO", _preferences->getBool(preference_gpio_locking_enabled)); printInputField(response, "PRDTMO", "Presence detection timeout (seconds; -1 to disable)", _preferences->getInt(preference_presence_detection_timeout), 10); response.concat(""); response.concat("
"); diff --git a/main.cpp b/main.cpp index ffe6d52..fd23802 100644 --- a/main.cpp +++ b/main.cpp @@ -9,6 +9,7 @@ #include "hardware/W5500EthServer.h" #include "hardware/WifiEthServer.h" #include "NukiOpenerWrapper.h" +#include "Gpio.h" NetworkLock* network = nullptr; NetworkOpener* networkOpener = nullptr; @@ -31,8 +32,6 @@ void networkTask(void *pvParameters) networkOpener->update(); webCfgServer->update(); delay(200); - -// Serial.print(F("#### ")); Serial.println(uxTaskGetStackHighWaterMark(NULL)); } } @@ -170,6 +169,11 @@ void setup() { nuki = new NukiWrapper("NukiHub", deviceId, bleScanner, network, preferences); nuki->initialize(); + + if(preferences->getBool(preference_gpio_locking_enabled)) + { + Gpio::init(nuki); + } } openerEnabled = preferences->getBool(preference_opener_enabled);