OK. Let’s step WAYYYYYY back.
When you call a function, you can pass data to it that they function may need. For example, when we call luup.log() to write something to the log, we have to tell it what we want to write, so we pass it one argument (also sometimes called a parameter), which is the string we want to write:
luup.log("Hello world!")
Now, luup.log() is defined something like this (within the context of the luup global variable):
function log( message )
What this says is, I’m defining a function called log, and whatever the caller passes to me as the first argument, receive it in a variable called message. So, within the code executing inside the function (called its scope) the variable named message will be defined. If we take our original example call, that message variable will contain the string “Hello World!”, and the function’s code can do whatever it needs to do with it.
Now in fact, luup.log() takes two arguments, the message to be written, and a logging level, so it’s actually defined like this:
function log( message, level )
In this case, we see that there is an additional argument, level. The list of arguments is comma-separated. Now, luup.log() has special code to test if that argument is passed at all, and if not, supply a default value, so most usage of luup.log() as we use it omits the level (the default value is 50). But we could call luup.log this way, and it would result in our message being output to the log at the highest error level (level 1):
luup.log( "Hello World!", 1 )
OK. Now let’s go back to your callback.
Calling luup.watch_variable puts the service/variable you specify on a list of watched variables. It’s not just one. It’s a list. The list remembers what service/variables are being watched, and the name of the callback function to call when that one changes. A bit simplified, but that’s the gist.
When a service/variable changes, Luup goes through that list, and if it finds that variable is being watched, calls the associated callback. When it calls the callback, it calls it with five arguments: the device number of the device whose service/variable changed, the service ID of the variable, the name of the variable, its current value (what it has been), and its new value (what its going to be). So, your callback function should be declared to receive all five of these variables. That’s what “lul_device, lul_service, lul_variable, etc.” is about. The fact that @akbooer used lul_whatever in his example and I used other names is just a reflection of style. In either case, the variables given in the function declaration are the ones that will be available inside the function. You make them special by choosing their names, but there is otherwise nothing special about the name. You can call them fred, wilma, barney, betty and bambam and you’ll still get all the data (and I’m dating myself).
So, when you declare your callback like this:
function watchCallback( lul_device, lul_service, lul_variable, lul_value_old, lul_value_new )
…you will have variables in the function code named lul_device containing the device number that Luup called about, lul_service containing the service Id, lul_variable containing the variable name, lul_value_old containing the old (prior to change) value, and lul_value_new containing the new (post-change) value. If we declare our function this way:
function watchCallback( a1, a2, a3, a4, a5 )
…then we would have variables named a1, a2, a3, a4 and a5 in the function scope to use, and since a1 is first, it has the device number; a2 then has the service ID, and a3 the variable name, and a4 the old value, and a5 the new value. These variable names are horrible because they don’t help you (or some future person reading your code) remember/know what the arguments are intended to mean, so this is wretched style and you should not do this, I’m merely illustrating the point that you can call these whatever you want (descriptive is better).
But regardless, all five values being passed to your callback are describing a single event, the change of one service variable that you have watched. But if you’ve watched many, you need to know which, so you need all five pieces of this data, all five arguments, to know which device, which service, which variable, and what values are changing. And no matter what service variable is being watched, when it changes, Luup will call your callback exactly this way.
For example, let’s say you are watching the setpoint temperature on a thermostat, and the last trip time on a sensor, and both watches have been given the same callback function (we’ll just call it “watchCallback”) to use. When the setpoint changes from 72 to 68, Luup will, in effect, call your callback with code that looks something like this:
watchCallback( thermostatDevNum, "urn:upnp-org:serviceId:TemperatureSetpoint1", "CurrentSetpoint", 72, 68 )
And then your sensor trips, Luup will call your callback function something like this:
watchCallback( sensorDevNum, "urn:micasaverde-com:serviceId:SecuritySensor1", "Tripped", 0, 1 )
So you see, Luup changes the arguments to your callback based on what has been changed–what it is telling you about. But the callback always gets five arguments, and the first one, whatever you name it, always gets the device number, and the second always gets the service ID, and the third the variable name, etc.
You can call luup.variable_watch() as many times as you want, but logically you would only call it once per variable you want to watch. Once Luup knows to watch that variable for you, you don’t need to tell it again. But you can call it for as many different service variables and devices as you need to watch. You also can use different callback fucntions for different variables and/or different devices (again, and name them as you choose), but for your simple use case, it’s really not necessary.
Hmm. Is this helping at all?