John,
How about I walk you through an example in the Caddx code?
I’ll refer to line numbers of this version of the JavaScript, this version of the Implementation file and this version of the Lua.
The Zones tab shows you which partition(s) each zone is in. The plugin has to ask the alarm panel for this information; this takes a moment. When the plugin Lua code gets the response, it passes the partition information back to the JavaScript. Result: the “Info” column that you see in the screenshot.
The JavaScript function that draws the Zones tab starts at J_CaddxNX584Security.js line 170. The table cell to be filled in is created at J_CaddxNX584Security.js line 219. Lines 267-274 steps through all the zones scheduling a delayed call to the JavaScript function scanExistingZone for each zone, staggered to not overwhelm the alarm panel’s serial protocol.
scanExistingZone (J_CaddxNX584Security.js line 277) does an Ajax call, which calls action I_CaddxNX584Security.xml lines 52-61. This runs the Lua function jobZoneScan at L_CaddxNX584Security.lua lines 1433 onwards. Most of the function is specific to the Caddx alarm panel; the important part is the return statement at L_CaddxNX584Security.lua line 1489. Returning 5 is the MiOS way of saying “ask me later”. What is immediately returned to the JavaScript is a Vera-generated job Id. This is collected by J_CaddxNX584Security.js line 290.
Now the Lua code waits for the alarm panel to respond with the zone’s partition information. This might take a while. While this is happening, the JavaScript code is in a recursive loop (waitForScanExistingZoneJob, J_CaddxNX584Security.js lines 304-332) asking the Lua code if there has been a response yet. As long as the Lua code keeps returning 5 (“Ask me later”) the function keeps recursing.
Eventually the alarm panel returns with the zone’s partition information, which is remembered at L_CaddxNX584Security.lua lines 1462-1465. The return value from the Lua code (line 1466) is now 4 (“Job completed successfully”). Now the partition information is known to the Lua code, and the JavaScript code can request it. The infinite recursion is broken out of at J_CaddxNX584Security.js line 326, calling getScanExistingZoneResult at line 334.
In getScanExistingZoneResult is another Ajax call, this time to the registered Luup callback lr_ZoneScan (registered at L_CaddxNX584Security.lua line 328). The request is picked up by L_CaddxNX584Security.lua lines 1410-1412. The Lua code there constructs a string that is valid JSON and returns it. This string contains the partition(s) that the zone is in. The JavaScript code collects this at J_CaddxNX584Security.js line 346, and sets the HTML on the web page (J_CaddxNX584Security.js line 355). Having done its job, the function exits.
As you can see, this is all quite roundabout, and only the last stage is actually a proper Luup registered callback. It has been the only way that I ever found to get information from the Lua code back to the JavaScript code without going through Luup variables. Even then there are limitations: if you have more than one device running the same plugin, then it’s not clear which device’s Lua context will receive the requests. That’s not a problem for the Caddx alarm plugin?most people have only one alarm system?but it required extra fiddling for the Combination Switch plugin.
Don’t spend too much effort trying to figure out the Lua in jobZoneScan(). It is complex mostly because of the fact that it has to reconstruct messages from the alarm panel interface one byte at a time. If you don’t have that problem in your plugin then in really is a case of just deciding when to return 5 or 4 from your Lua: 5 until you have the result, then 4.
Edit: it occurs to me that your original post may not even need a full-fledged asynchronous job. If your Lua code can get its answer quickly, it can simply return the answer as a JSON-formatted string. Make the action rather than . I’ve never done this but I think it works.