luup.watch callback
-
Hoping someone can point me in the right direction. Per the code below, I am trying to run a function conditionally ("modeTableAction") when a watch callback triggers. In this case, the watch is on a reactor group. What I don't understand and cannot find any info on, is how to pass parameters to the function/callback. The lua file "myStartupLua" is called from openluup startup with a global require statement and this allows me to call the functions in the file from Reactor activities.
Do I need to embed a function (that contains the parameters) within the callback function so that the callback then calls the embedded function and its parameters?
module("myStartUpLua", package.seeall) function _G.turnOffModes(myMode) -- reactor 'and' group that checks for motion relay on and 'mode off' virtual switch is on. local porchSensorStatus = luup.variable_get("urn:toggledbits-com:serviceId:ReactorGroup", "GroupStatus_grp1a1dd8um", 160) -- modes and their device numbers local modeTable = { ['Office'] = '203', ['Garage'] = '204', ['Off'] = '223', ['Outdoors'] = '202', ['Guest'] = '190', ['Bedtime'] = '209', ['Morning'] = '217', ['Standard'] = '215', ['Party'] = '199', ['Manual'] = '206' } function modeTableAction( t, myMode ) for k, v in pairs( t ) do local lightDeviceID = v if ( k == myMode ) then local resultCode, resultString, job, returnArguments = luup.call_action("urn:upnp-org:serviceId:SwitchPower1","SetTarget",{ newTargetValue="1" },lightDeviceID) luup.log('Turn on ' .. k .. ' ' .. lightDeviceID ,50) else local resultCode, resultString, job, returnArguments = luup.call_action("urn:upnp-org:serviceId:SwitchPower1","SetTarget",{ newTargetValue="0" },lightDeviceID) luup.log('Turn off ' .. k .. ' ' .. lightDeviceID ,50) end end end local function watchPorchRelay () if porchSensorStatus == 1 then -- motion relay on and 'mode off' virtual switch is on -- watch and wait for the vStatus to go to 0 luup.variable_watch("modeTableAction","urn:toggledbits-com:serviceId:ReactorGroup", "GroupStatus_grp1a1dd8um", 160) else -- proceed directly with turning off virtual switches. modeTableAction (modeTable, myMode) end end watchPorchRelay() end
-
Yes, this can be a challenge. It is, as you say, a matter of scoping correctly so that you can access the information you want.
It's for this reason that @therealdb suggested adding an additional parameter to the luup.register_handler call in our discussion here:
https://smarthome.community/topic/316/openluup-mqtt-server/87
The same could be done for variable watches, but the solutions I originally offered in the above thread could still be used.
-
OK thanks for that. I don't think there's a need to amend the luup call. In my example, I can easily handle the parameters with an awareness of scope. I wrote the code that way to demonstrate the problem and allow for some future parameterizing, but I see now I need to do this using only scope and closures.
Why did the vera engineers design "some" of their callbacks this way (call_delay allows parameters). Is there an advantage to not using parameters (speed, rigor etc) . It's been noted many times in the forums how awkward it is to not be able to pass functions in callbacks, only a string of the name of the function--forcing global scope on callbacks. What do you believe the developers were thinking when they made these two design choices as the underlying code is in C or C++, and that would give them enormous flexibility to do otherwise. Parameters would also have made the code more readable, and as a hobbyist, I find that really important when trying to decipher what someone is doing with a given section of code.
-
I suspect that the implementations were done at different times by different people, with no real thought to the wider architecture The inconsistencies in Vera/MiOS/Luup are legion (and legendary.) My guess on the use of named globals is that it helps in some way because the individual plugins run in separate threads. This was not something that I needed to do in openLuup and, indeed, at the object-level API you use function references rather than names.
-
Agree here completely. I suspect, unfortunately, that the early developers had no idea what a "closure" was or how to use it, so they just punted and did the easiest thing. The real sin is that it's easy to tell the difference between a parameter that is a string (name of a global function) and one that is a function reference or closure, so they could have easily improved the operation of these API functions at any time without creating any incompatibility with older versions/styles, but instead they just ignored and perpetuated it. They weren't big enough consumers of their own product to really get in touch with its inconveniences, and for the developers that did note them, well, we're just complainers.