luup.variable_watch
-
Hi AK,
I can't find any info on how a variable watch actually ends.
I have the following variable watch on an alarm panel plugin UPnP variable. The code is part of some extended startup lua:
luup.variable_watch("waitForZoneToClose","urn:micasaverde-com:serviceId:EVL3VistaAlarmPanel1", "FaultedZoneNames", 7)
In the same startup lua, the global function "waitForZoneToClose" is called when the "FaultedZoneNames" variable changes, but this same function is also called at the start of a routine that determines what zones are actually faulted on the alarm panel.
openZoneCount= waitForZoneToClose(7, "urn:micasaverde-com:serviceId:EVL3VistaAlarmPanel1", "FaultedZoneNames" , "","")
So although the luup watch variables are included in the function params, they are not used within the function:
function waitForZoneToClose(dev_id, service, variable, old_val, new_val) openZoneCount = getOpenZones() --retrieves open zone names on panel, and zones to bypass per mode setting if openZoneCount > 0 then -- there are open zones buildReservedZonesTable() -- run routine to pop bypass and vent zones from the zonesToClose stack removeReservedZones() openZoneCount = tablelength(tZonesToClose) -- run the count again to see if any zone was popped off the stack during removeReservedZones end return openZoneCount end
Because I run the function recursively ie. when the variable that holds the open zones changes, I rerun the function that detects open zones, and if any relevant zones are still open, the code for the same watch is ran again, to detect if any zones have changed status, this before trying to auto arm the panel. So there might be a situation where two or more zones need to be closed before the panel will arm, and it takes real time to physically close each zone, one by one, and as each closes, the callback would trigger again.
Hope that makes sense.
I wasn't clear if a variable watch ends when the watched variable changes and the code then proceeds. Or do you have to end the watch via code somehow? I was concerned about a possible condition where watch upon watch would be added to memory until a luup reload would clear the watches, or do the watches end and self-cleanup when the callback function is called.
-
There is, of course, no requirement to use any callback parameters – although it might be cleaner to remove unused ones, I sometimes leave them there as documentation.
It's often enough to know that a variable change has taken place, just as a trigger to other, more complex, actions, like polling other variables and so on, as you do above.
I'm not sure I fully understand your question. The watched variable is just a trigger. The callback routine runs until it exits. In openLuup, this is done asynchronously from the event that caused the trigger (ie. at a later time) in order for the initially running bit of code to do everything it needed to do before any triggered actions take place.
-
There is, of course, no requirement to use any callback parameters – although it might be cleaner to remove unused ones, I sometimes leave them there as documentation.
It's often enough to know that a variable change has taken place, just as a trigger to other, more complex, actions, like polling other variables and so on, as you do above.
I'm not sure I fully understand your question. The watched variable is just a trigger. The callback routine runs until it exits. In openLuup, this is done asynchronously from the event that caused the trigger (ie. at a later time) in order for the initially running bit of code to do everything it needed to do before any triggered actions take place.
@akbooer Yes, I understand the callback and how it is triggered. The question is once a watch is established (in this case during startup lua), can it be removed. If so, how is that done. Secondly, what happens when you re-run the code that places a watch on a specific variable. Do the watches stack up in memory, or is the previous watch simply replaced by the new call. Or perhaps the new watch is ignored. I don't know as I can't find any documentation on how this works.
I only want the callback triggered under specific conditions ie. there are certain conditions where the watched variable should not trigger the callback routine-- such as when zones are opening and closing when there is no intention to arm the security panel. If I can't remove a watch and then re-add it later, I'm guessing that I have to account for those conditions within callback function. Is that correct?
-
@akbooer Yes, I understand the callback and how it is triggered. The question is once a watch is established (in this case during startup lua), can it be removed. If so, how is that done. Secondly, what happens when you re-run the code that places a watch on a specific variable. Do the watches stack up in memory, or is the previous watch simply replaced by the new call. Or perhaps the new watch is ignored. I don't know as I can't find any documentation on how this works.
I only want the callback triggered under specific conditions ie. there are certain conditions where the watched variable should not trigger the callback routine-- such as when zones are opening and closing when there is no intention to arm the security panel. If I can't remove a watch and then re-add it later, I'm guessing that I have to account for those conditions within callback function. Is that correct?
@buxton said in luup.variable_watch:
I only want the callback triggered under specific conditions ie. there are certain conditions where the watched variable should not trigger the callback routine-- such as when zones are opening and closing when there is no intention to arm the security panel. If I can't remove a watch and then re-add it later, I'm guessing that I have to account for those conditions within callback function. Is that correct?
Yes, in openLuup, using the luup.variable_watch() function, they stack up. Vera had no way of removing a variable watch. The object-oriented level of openLuup does have methods to do that, but undoubtedly the best approach is simply to register once and handle all the yes/no logic in the callback routine itself.
-
@buxton said in luup.variable_watch:
I only want the callback triggered under specific conditions ie. there are certain conditions where the watched variable should not trigger the callback routine-- such as when zones are opening and closing when there is no intention to arm the security panel. If I can't remove a watch and then re-add it later, I'm guessing that I have to account for those conditions within callback function. Is that correct?
Yes, in openLuup, using the luup.variable_watch() function, they stack up. Vera had no way of removing a variable watch. The object-oriented level of openLuup does have methods to do that, but undoubtedly the best approach is simply to register once and handle all the yes/no logic in the callback routine itself.
@akbooer OK thanks, that's what I needed to know.
One final question if you could. How does scope affect a watch called from start-up lua? I'm asking because I imagine the scope for a watch is plugin specific, and therefore is confined to the plugin.
The watch will be created in the initialization code of a global module, that is in turn referenced in start-up lua ie. "_G.myStartUpLua = require("myStartUpLua") "
This module contains functions that are called from Reactor activities similar to this:
Will the global watch callback function be visible to the watch if both are created within "myStartUpLua".
-
I'm not familiar with Reactor (or MSR) so I'm not sure of the mechanism...
In Vera, different plugins, and Startup Lua (along with Lua Test and scenes) all have different threads, so entirely different Lua instances – this is one reason why plugins take up so much memory space.
Under openLuup, there is only one Lua instance, but all those things are given separate global contexts, so there is no conflict between global names.
-
@akbooer OK thanks, that's what I needed to know.
One final question if you could. How does scope affect a watch called from start-up lua? I'm asking because I imagine the scope for a watch is plugin specific, and therefore is confined to the plugin.
The watch will be created in the initialization code of a global module, that is in turn referenced in start-up lua ie. "_G.myStartUpLua = require("myStartUpLua") "
This module contains functions that are called from Reactor activities similar to this:
Will the global watch callback function be visible to the watch if both are created within "myStartUpLua".
@buxton Yeah, running lua within the Reactor plugin/MSR is an incredibly powerful feature that, combined with expressions, pretty much allows you to do whatever you want to do. A wonderful piece of software.
Now I need to figure out how to construct the closure that will surround the watch callback function. Tricky, because there are so many variables that go into deciding when the routine should branch, and when branching should be avoided.
-
I'm not familiar with Reactor (or MSR) so I'm not sure of the mechanism...
In Vera, different plugins, and Startup Lua (along with Lua Test and scenes) all have different threads, so entirely different Lua instances – this is one reason why plugins take up so much memory space.
Under openLuup, there is only one Lua instance, but all those things are given separate global contexts, so there is no conflict between global names.