diff --git a/Gpio.cpp b/Gpio.cpp index 0ad2c4a..c3b2601 100644 --- a/Gpio.cpp +++ b/Gpio.cpp @@ -74,6 +74,14 @@ void Gpio::init() pinMode(entry.pin, INPUT_PULLUP); attachInterrupt(entry.pin, isrDeactivateRtoCm, FALLING); break; + case PinRole::InputDeactivateRTO: + pinMode(entry.pin, INPUT_PULLUP); + attachInterrupt(entry.pin, isrDeactivateRTO, FALLING); + break; + case PinRole::InputDeactivateCM: + pinMode(entry.pin, INPUT_PULLUP); + attachInterrupt(entry.pin, isrDeactivateCM, FALLING); + break; case PinRole::OutputHighLocked: case PinRole::OutputHighUnlocked: case PinRole::OutputHighMotorBlocked: @@ -199,6 +207,10 @@ String Gpio::getRoleDescription(PinRole role) const return "Input: Activate CM"; case PinRole::InputDeactivateRtoCm: return "Input: Deactivate RTO/CM"; + case PinRole::InputDeactivateRTO: + return "Input: Deactivate RTO"; + case PinRole::InputDeactivateCM: + return "Input: Deactivate CM"; case PinRole::OutputHighLocked: return "Output: High when locked"; case PinRole::OutputHighUnlocked: @@ -327,6 +339,20 @@ void Gpio::isrDeactivateRtoCm() _debounceTs = millis() + _debounceTime; } +void Gpio::isrDeactivateRTO() +{ + if(millis() < _debounceTs) return; + _inst->notify(GpioAction::DeactivateRTO, -1); + _debounceTs = millis() + _debounceTime; +} + +void Gpio::isrDeactivateCM() +{ + if(millis() < _debounceTs) return; + _inst->notify(GpioAction::DeactivateCM, -1); + _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 1203c66..a7823da 100644 --- a/Gpio.h +++ b/Gpio.h @@ -16,6 +16,8 @@ enum class PinRole InputActivateRTO, InputActivateCM, InputDeactivateRtoCm, + InputDeactivateRTO, + InputDeactivateCM, OutputHighLocked, OutputHighUnlocked, OutputHighMotorBlocked, @@ -38,6 +40,8 @@ enum class GpioAction ActivateRTO, ActivateCM, DeactivateRtoCm, + DeactivateRTO, + DeactivateCM, GeneralInput }; @@ -88,6 +92,8 @@ private: PinRole::InputActivateRTO, PinRole::InputActivateCM, PinRole::InputDeactivateRtoCm, + PinRole::InputDeactivateRTO, + PinRole::InputDeactivateCM, PinRole::OutputHighLocked, PinRole::OutputHighUnlocked, PinRole::OutputHighRtoActive, @@ -110,6 +116,8 @@ private: static void IRAM_ATTR isrActivateRTO(); static void IRAM_ATTR isrActivateCM(); static void IRAM_ATTR isrDeactivateRtoCm(); + static void IRAM_ATTR isrDeactivateRTO(); + static void IRAM_ATTR isrDeactivateCM(); std::vector> _callbacks; diff --git a/MqttTopics.h b/MqttTopics.h index 48884a0..eb707a1 100644 --- a/MqttTopics.h +++ b/MqttTopics.h @@ -18,7 +18,7 @@ #define mqtt_topic_query_battery "/lock/query/battery" #define mqtt_topic_query_lockstate_command_result "/lock/query/lockstateCommandResult" #define mqtt_topic_lock_binary_state "/lock/binaryState" -#define mqtt_topic_lock_continous_mode "/lock/continousMode" +#define mqtt_topic_lock_continuous_mode "/lock/continuousMode" #define mqtt_topic_lock_trigger "/lock/trigger" #define mqtt_topic_lock_last_lock_action "/lock/lastLockAction" #define mqtt_topic_lock_log "/lock/log" diff --git a/Network.cpp b/Network.cpp index 631b8b5..5452074 100644 --- a/Network.cpp +++ b/Network.cpp @@ -1166,21 +1166,24 @@ void Network::publishHASSConfigContinuousMode(char *deviceType, const char *base if (discoveryTopic != "") { - publishHassTopic("binary_sensor", + publishHassTopic("switch", "continuous_mode", uidString, "_continuous_mode", "Continuous mode", name, baseTopic, - String("~") + mqtt_topic_lock_continous_mode, + String("~") + mqtt_topic_lock_continuous_mode, deviceType, "lock", "", "", - "", - {{"pl_on", "on"}, - {"pl_off", "off"}}); + String("~") + mqtt_topic_lock_action, + {{ "enabled_by_default", "false" }, + {"state_on", "on"}, + {"state_on", "off"}, + {"pl_on", "activateCM"}, + {"pl_off", "deactivateCM"}}); } } diff --git a/NetworkOpener.cpp b/NetworkOpener.cpp index 0705943..7d2bdc0 100644 --- a/NetworkOpener.cpp +++ b/NetworkOpener.cpp @@ -210,14 +210,7 @@ void NetworkOpener::publishKeyTurnerState(const NukiOpener::OpenerState& keyTurn if((_firstTunerStatePublish || keyTurnerState.lockState != lastKeyTurnerState.lockState || keyTurnerState.nukiState != lastKeyTurnerState.nukiState) && keyTurnerState.lockState != NukiOpener::LockState::Undefined) { - if(keyTurnerState.nukiState == NukiOpener::State::ContinuousMode) - { - publishString(mqtt_topic_lock_state, "ContinuousMode"); - } - else - { - publishString(mqtt_topic_lock_state, str); - } + publishString(mqtt_topic_lock_state, str); if(_haEnabled) { @@ -229,8 +222,10 @@ void NetworkOpener::publishKeyTurnerState(const NukiOpener::OpenerState& keyTurn if(keyTurnerState.nukiState == NukiOpener::State::ContinuousMode) { + publishString(mqtt_topic_lock_continuous_mode, "on"); json["continuous_mode"] = 1; } else { + publishString(mqtt_topic_lock_continuous_mode, "off"); json["continuous_mode"] = 0; } @@ -291,12 +286,9 @@ void NetworkOpener::publishState(NukiOpener::OpenerState lockState) { publishString(mqtt_topic_lock_ha_state, "unlocked"); publishString(mqtt_topic_lock_binary_state, "unlocked"); - publishString(mqtt_topic_lock_continous_mode, "on"); } else { - publishString(mqtt_topic_lock_continous_mode, "off"); - switch (lockState.lockState) { case NukiOpener::LockState::Locked: @@ -307,7 +299,7 @@ void NetworkOpener::publishState(NukiOpener::OpenerState lockState) case NukiOpener::LockState::Open: publishString(mqtt_topic_lock_ha_state, "unlocked"); publishString(mqtt_topic_lock_binary_state, "unlocked"); - break; + break; case NukiOpener::LockState::Opening: publishString(mqtt_topic_lock_ha_state, "unlocking"); publishString(mqtt_topic_lock_binary_state, "unlocked"); @@ -537,7 +529,7 @@ void NetworkOpener::publishHASSConfig(char* deviceType, const char* baseTopic, c _network->publishHASSConfig(deviceType, baseTopic, name, uidString, availabilityTopic.c_str(), false, lockAction, unlockAction, openAction); _network->publishHASSConfigRingDetect(deviceType, baseTopic, name, uidString); - _network->publishHASSConfigContinuousMode(deviceType, baseTopic, name, uidString); + _network->publishHASSConfigContinuousMode(deviceType, baseTopic, name, uidString); _network->publishHASSConfigSoundLevel(deviceType, baseTopic, name, uidString); _network->publishHASSBleRssiConfig(deviceType, baseTopic, name, uidString); } @@ -559,7 +551,7 @@ void NetworkOpener::publishKeypad(const std::list& entrie basePath.concat("/code_"); basePath.concat(std::to_string(index).c_str()); publishKeypadEntry(basePath, entry); - + auto jsonEntry = json.add(); jsonEntry["id"] = entry.codeId; diff --git a/NukiOpenerWrapper.cpp b/NukiOpenerWrapper.cpp index 327ad49..fab2f54 100644 --- a/NukiOpenerWrapper.cpp +++ b/NukiOpenerWrapper.cpp @@ -291,6 +291,16 @@ void NukiOpenerWrapper::deactivateRtoCm() } } +void NukiOpenerWrapper::deactivateRTO() +{ + _nextLockAction = NukiOpener::LockAction::DeactivateRTO; +} + +void NukiOpenerWrapper::deactivateCM() +{ + _nextLockAction = NukiOpener::LockAction::DeactivateCM; +} + bool NukiOpenerWrapper::isPinSet() { return _nukiOpener.getSecurityPincode() != 0; @@ -347,12 +357,10 @@ void NukiOpenerWrapper::updateKeyTurnerState() { Log->println(F("Continuous Mode")); } - else - { - char lockStateStr[20]; - lockstateToString(_keyTurnerState.lockState, lockStateStr); - Log->println(lockStateStr); - } + + char lockStateStr[20]; + lockstateToString(_keyTurnerState.lockState, lockStateStr); + Log->println(lockStateStr); } if(_publishAuthData) @@ -535,6 +543,12 @@ void NukiOpenerWrapper::gpioActionCallback(const GpioAction &action, const int& case GpioAction::DeactivateRtoCm: nukiOpenerInst->deactivateRtoCm(); break; + case GpioAction::DeactivateRTO: + nukiOpenerInst->deactivateRTO(); + break; + case GpioAction::DeactivateCM: + nukiOpenerInst->deactivateCM(); + break; } } @@ -740,16 +754,16 @@ void NukiOpenerWrapper::setupHASS() String baseTopic = _preferences->getString(preference_mqtt_opener_path); char uidString[20]; itoa(_nukiConfig.nukiId, uidString, 16); - - if (_preferences->getBool(preference_opener_continuous_mode)) + + if (_preferences->getBool(preference_opener_continuous_mode)) { _network->publishHASSConfig("Opener",baseTopic.c_str(),(char*)_nukiConfig.name,uidString, "deactivateCM","activateCM","electricStrikeActuation"); } - else + else { _network->publishHASSConfig("Opener",baseTopic.c_str(),(char*)_nukiConfig.name,uidString, "deactivateRTO","activateRTO","electricStrikeActuation"); } - + _hassSetupCompleted = true; Log->println("HASS setup for opener completed."); diff --git a/NukiOpenerWrapper.h b/NukiOpenerWrapper.h index b616977..619ce04 100644 --- a/NukiOpenerWrapper.h +++ b/NukiOpenerWrapper.h @@ -22,12 +22,14 @@ public: void activateRTO(); void activateCM(); void deactivateRtoCm(); + void deactivateRTO(); + void deactivateCM(); bool isPinSet(); void setPin(const uint16_t pin); void unpair(); - + void disableHASS(); void disableWatchdog(); @@ -63,7 +65,7 @@ private: void readConfig(); void readAdvancedConfig(); - + void setupHASS(); void printCommandResult(Nuki::CmdResult result); diff --git a/README.md b/README.md index 22aecdb..b938672 100644 --- a/README.md +++ b/README.md @@ -199,7 +199,9 @@ can be configured for a specific role: - Input: Electric strike actuation: When connect to Ground, an electric strike actuation command is sent to the opener (open door for configured amount of time) - Input: Activate RTO: When connect to Ground, Ring-to-open is activated (opener) - Input: Activate CM: When connect to Ground, Continuous mode is activated (opener) -- Input: Deactivate RTO/CM: Disable RTO or CM, depending on which is active +- Input: Deactivate RTO/CM: Disable RTO or CM, depending on which is active (opener) +- Input: Dectivate RTO: When connect to Ground, Ring-to-open is deactivated (opener) +- Input: Dectivate CM: When connect to Ground, Continuous mode is deactivated (opener) - Output: High when locked: Outputs a high signal when the door is locked - Output: High when unlocked: Outputs a high signal when the door is unlocked - Output: High when motor blocked: Outputs a high signal when the motor is blocked (lock)