Can I make a call_timer callback from a lua module?

I’m writing a lua module and I would like to have a function to be called at regular intervals. Normally I would use luup.call_timer, but that does not appear to work inside a module. Is there a workaround or a better way? I am hoping not to have to make an interval trigger in the UI call my luup module.

test.lua, located in /usr/lib/lua :

module(..., package.seeall)

function Initialize()
	luup.log("Setting timer...")
	luup.call_timer("TimerCallback", 1, "10", "", "")
end

function TimerCallback()
	luup.log("TimerCallback()")
end

Then I run the following from Test luup code:

require("test")
test.Initialize()

The first part works:
luup_log:0: Setting timer…

But after 10 seconds, the following error occurs:
LuaInterface::CallFunction_Timer-5 function TimerCallback failed attempt to call a nil value

I am using UI5, firmware 1.5.346

Any help would be appreciated.

The timer callback method must be a public function on your plugin. In turn, that method can call the one on your module/library, but call_timer cannot see the one in the module.

One thing I haven’t tried is calling it via “test.TimerCallback”, but that would lockin the uses to having the caller have a variable called test (etc) if it worked.

The way I normally do this is to copy the function from the module into the global symbol table explicitly.

t =require("test")
CallBackTimer = t.CallBackTimer

See one of my plugins, I think the Countdown Timer, for a working example.

Thanks for the response, guessed and futzle.
I’ve given it some thought, and I am not sure if your responses addresses the question if a module (not a plugin or global code) can request a callback to one of its “member functions”. I don’t believe a module can use request on itself, or insert itself into the global symbol table, but please correct me if I’m wrong.

@futzle, I really did like the way your Countdown Timer survives a luup restart, and I am playing with the thought of making a device that would act as a “timer pool” usable from luup code, similar to how call_timer works. The difference would be restart persistence and instead of the first string being a the name of a global function, it would be an arbitrary string of code. I discovered that it’s possible to make an “eval” in the following manner:

loadstring("require('test'); test.TimerCallback()")

Function name and an optional module name could be two parameters to the timer function. It’s just a question of storing a string of code and making it run after a certain amount of time. We will see what comes out of this. :slight_smile:

Lua has a special variable _G which supposedly always contains the global symbol table. It might be useful for the module to reach into the namespace of the code that included it and make an entry point for a call_timer().

Totally untested. I just remember seeing it a few days ago on stackoverflow.

Wow, that actually worked! Thanks futzle. I imagine I could use the same trick on luup.variable_watch which had similar symptoms.

test.lua

module(..., package.seeall)

function Initialize()
	luup.log("Setting timer...")
	_G["TimerCallback"] = TimerCallback
	luup.call_timer("TimerCallback", 1, "10", "", "")
end

function TimerCallback()
	luup.log("TimerCallback()")
end

Test luup code:

require("test") test.Initialize()

That’s at least in part what he package.seeall declaration is supposed to let you do. Call_timer (etc) just build a Lua method call against the top level, so anything visible there, or made visible as the way you do now, is callable.

Call_action works the same way, you’d just have to know the ‘special’ method name that generated for each ACTION handler block.