diff --git a/presence-light/PresenceLight.cpp b/presence-light/PresenceLight.cpp index 1e9b00d2..f8d4539c 100644 --- a/presence-light/PresenceLight.cpp +++ b/presence-light/PresenceLight.cpp @@ -60,6 +60,9 @@ bool PresenceLight::init(Flows::PNodeInfo info) settingsIterator = info->info->structValue->find("process-false"); if(settingsIterator != info->info->structValue->end()) _switchOffOnInFalse = settingsIterator->second->booleanValue; + settingsIterator = info->info->structValue->find("keep-on"); + if(settingsIterator != info->info->structValue->end()) _keepOn = settingsIterator->second->booleanValue; + return true; } catch(const std::exception& ex) @@ -221,6 +224,7 @@ void PresenceLight::timer() setNodeData("onTo", std::make_shared(-1)); _manuallyEnabled.store(false, std::memory_order_release); + _manuallyDisabled.store(false, std::memory_order_release); setNodeData("manuallyEnabled", std::make_shared(false)); } else if(getLightState()) @@ -238,7 +242,7 @@ void PresenceLight::timer() _lastLightEvent.store(BaseLib::HelperFunctions::getTime(), std::memory_order_release); Flows::PVariable outputMessage = std::make_shared(Flows::VariableType::tStruct); - bool lightState = onTo > time && (_enabled.load(std::memory_order_acquire) || _manuallyEnabled.load(std::memory_order_acquire)); + bool lightState = onTo > time && (_enabled.load(std::memory_order_acquire) || _manuallyEnabled.load(std::memory_order_acquire)) && !_manuallyDisabled.load(std::memory_order_acquire); outputMessage->structValue->emplace("payload", std::make_shared(_booleanStateValue.load(std::memory_order_acquire) ? lightState : (lightState ? _stateValue.load(std::memory_order_acquire) : 0))); output(0, outputMessage); @@ -269,7 +273,7 @@ void PresenceLight::timer() _lastLightEvent.store(BaseLib::HelperFunctions::getTime(), std::memory_order_release); Flows::PVariable outputMessage = std::make_shared(Flows::VariableType::tStruct); - bool lightState = onTo > time && (_enabled.load(std::memory_order_acquire) || _manuallyEnabled.load(std::memory_order_acquire)); + bool lightState = onTo > time && (_enabled.load(std::memory_order_acquire) || _manuallyEnabled.load(std::memory_order_acquire)) && !_manuallyDisabled.load(std::memory_order_acquire); outputMessage->structValue->emplace("payload", std::make_shared(_booleanStateValue.load(std::memory_order_acquire) ? lightState : (lightState ? _stateValue.load(std::memory_order_acquire) : 0))); output(0, outputMessage); @@ -320,7 +324,9 @@ bool PresenceLight::getLightState() auto onTo = _onTo.load(std::memory_order_acquire); auto alwaysOnTo = _alwaysOnTo.load(std::memory_order_acquire); auto alwaysOffTo = _alwaysOffTo.load(std::memory_order_acquire); - return ((_enabled.load(std::memory_order_acquire) || _manuallyEnabled.load(std::memory_order_acquire)) && onTo != -1 && BaseLib::HelperFunctions::getTime() < onTo && + return ((_enabled.load(std::memory_order_acquire) || _manuallyEnabled.load(std::memory_order_acquire)) && + !_manuallyDisabled.load(std::memory_order_acquire) && + onTo != -1 && BaseLib::HelperFunctions::getTime() < onTo && (alwaysOffTo == -1 || (alwaysOffTo != 0 && (BaseLib::HelperFunctions::getTime() >= alwaysOffTo)))) || alwaysOnTo == 0 || (alwaysOnTo != -1 && BaseLib::HelperFunctions::getTime() < alwaysOnTo); } @@ -358,6 +364,10 @@ void PresenceLight::input(const Flows::PNodeInfo info, uint32_t index, const Flo { bool enabled = _enabled.load(std::memory_order_acquire); if(enabled == inputValue) return; + if(!inputValue && _keepOn) + { + _manuallyEnabled.store(true, std::memory_order_release); + } _enabled.store(inputValue, std::memory_order_release); setNodeData("enabled", std::make_shared(inputValue)); } @@ -474,13 +484,12 @@ void PresenceLight::input(const Flows::PNodeInfo info, uint32_t index, const Flo _stateValue.store(1, std::memory_order_release); setNodeData("stateValue", input); } - else if(input->type == Flows::VariableType::tInteger64 && input->integerValue64 > 0) + else if(input->type == Flows::VariableType::tInteger64) { _booleanStateValue.store(false, std::memory_order_release); _stateValue.store(input->integerValue64, std::memory_order_release); setNodeData("stateValue", input); } - return; } else if(index == 6) //Toggle { @@ -492,10 +501,17 @@ void PresenceLight::input(const Flows::PNodeInfo info, uint32_t index, const Flo setNodeData("stateValue", input); } + if(!_booleanStateValue.load(std::memory_order_acquire) && input->type == Flows::VariableType::tBoolean) + { + _out->printWarning(R"(Warning: Got boolean input on "TG", but "SVAL" is set to a light profile (i. e. to an Integer).)"); + return; + } + auto onTo = _onTo.load(std::memory_order_acquire); - if((!_booleanStateValue.load(std::memory_order_release) && inputValue) || onTo == -1) + if((!_booleanStateValue.load(std::memory_order_acquire) && inputValue) || onTo == -1) { _manuallyEnabled.store(true, std::memory_order_release); + _manuallyDisabled.store(false, std::memory_order_release); setNodeData("manuallyEnabled", std::make_shared(true)); auto onTime = _onTime; @@ -508,6 +524,8 @@ void PresenceLight::input(const Flows::PNodeInfo info, uint32_t index, const Flo } else { + _manuallyEnabled.store(false, std::memory_order_release); + _manuallyDisabled.store(true, std::memory_order_release); _onTo.store(-1, std::memory_order_release); setNodeData("manuallyEnabled", std::make_shared(false)); diff --git a/presence-light/PresenceLight.h b/presence-light/PresenceLight.h index f145e4d5..87ea0001 100644 --- a/presence-light/PresenceLight.h +++ b/presence-light/PresenceLight.h @@ -55,6 +55,7 @@ class PresenceLight: public Flows::INode uint32_t _alwaysOffTime = 21600000; int64_t _lastInput = -1; bool _switchOffOnInFalse = false; + bool _keepOn = false; //}}} std::atomic _lastLightEvent{-1}; @@ -67,7 +68,9 @@ class PresenceLight: public Flows::INode std::atomic_bool _enabled{true}; std::atomic_bool _manuallyEnabled{false}; + std::atomic_bool _manuallyDisabled{false}; std::atomic _onTo{-1}; + int64_t _inBlockedUntil = 0; std::atomic _alwaysOnTo{-1}; std::atomic _alwaysOffTo{-1}; diff --git a/presence-light/locales/en-US/presence-light b/presence-light/locales/en-US/presence-light index 84c92396..4cb51d25 100644 --- a/presence-light/locales/en-US/presence-light +++ b/presence-light/locales/en-US/presence-light @@ -9,7 +9,8 @@ "always-on-time2": "Time in seconds", "always-off-time": "Always off time", "always-off-time2": "Time in seconds", - "process-false": "Switch light off immediately, when \"IN\" is set to false." + "process-false": "Switch light off immediately, when \"IN\" is set to \"false\".", + "keep-on": "Keep light on when \"EN\" is set to \"false\"." }, "paletteHelp": "

This node automatically switches lights on or off depending on presence.

", "help": "

This node automatically switches lights on or off depending on presence. A presence signal (true) on IN sets S to SVAL (true of a profile number greater 0). S is reset to false or 0 after On time. An input of true on ON sets S to SVAL regardless of other inputs. ON is automatically reset after Always on time. When this happens, RES is set to true and S is set depending on IN and On time. An input of true on OFF sets S to false or 0 regardless of other inputs. OFF is automatically reset after Always off time. When this happens, RES is set to true and S is set depending on IN and On time. Setting Always on time or Always off time to 0, disables the timer so the lights will stay on or off until ON or OFF are set to false. Setting EN to false disables processing of IN for example during daytime. IN2 also sets S to true but an input of false to IN2 immediately sets S to false or 0 and resets the On time timer. TG toggles s setting it to SVAL and starting the timer when it is false and immediately setting it to false resetting the timer when it is true or greater 0. TG also works with profile (scene) numbers. 0 is recognized as the on/off profile toggling the last input scene number greater than 0. Any other number switches to that profile and also sets SVAL.

Note: The inputs are rate limited to one input per seconds to avoid too fast outputs.

On time, Always on time and Always off time can also be set dynamically by setting $message['onTime'], $message['alwaysOnTime'] or $message['alwaysOffTime']

", diff --git a/presence-light/presence-light.hni b/presence-light/presence-light.hni index d5162cdd..919f4fa1 100644 --- a/presence-light/presence-light.hni +++ b/presence-light/presence-light.hni @@ -31,6 +31,11 @@ +
+ + + +