Passing parameters to a script

Hi,

I want to create a script that I can call from various rules, to avoid duplicating code.
I’ve found this article, explaining what to do. I’m not sure if the information in there is still relevant (given OH2).

I started with a small POC, just to see if I got the basics right (including passing 2 parameters from a rule to a script).

I create a file called “sendsms.script” and I’ve put it in the scripts-folder.
The content is this:


val org.eclipse.xtext.xbase.lib.Functions$Function2 sendsms = [
	org.openhab.core.library.items.StringItem sms_text,
	org.openhab.core.library.items.StringItem sms_recipient |	
			logInfo ("script", "The sendsms script is called")
			logInfo ("script", "First parameter =" + sms_text)	
			logInfo ("script", "Second parameter =" + sms_recipient)	
	]

My openhab.log shows:

2017-05-30 16:03:22.991 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model 'sendsms.script'
2017-05-30 16:03:23.183 [INFO ] [el.core.internal.ModelRepositoryImpl] - Validation issues found in configuration model 'sendsms.script', using it anyway:
The value of the local variable sms is not used
Function2 is a raw type. References to generic type Function2<P1, P2, Result> should be parameterized

I guess the validation issue is ok, since I am not doing anything besides a logInfo.
I’m not sure if I understand the second part (Function2 is a raw type).

In a rule, I try to call the script using:

sendsms.apply("some text", "some recipient")

However, when I execute the rule, I get:

2017-05-30 16:05:59.124 [ERROR] [.script.engine.ScriptExecutionThread] - Rule 'test': An error occured during the script execution: The name 'sendsms' cannot be resolved to an item or type.

Is there some more documentation or other help, allowing me to execute a script from a rule with 2 parameters?

I think, your Lambda is not in the correct syntax. You may want to look into this:

https://community.openhab.org/t/reusable-functions-a-simple-lambda-example-with-copious-notes/15888

Thanks,
I was searching for “scripts” on this forum, not “lambda’s”, so I guess I overlooked this one.

I have now adapted it, which results in the following sendsms.script:

// The Rules DSL has deprecated importing whole libraries using *, import those classes you actually
// use individually.
import org.eclipse.xtext.xbase.lib.Functions

// Those who come from Java will recognize this syntax. The < > lets us define the types of the 
// arguments as well as the return value. If you plan on using this syntax make sure the last line in the 
// lambda matches the type of the last item in the < >
//
// You no longer need supply the types for the arguments (stuff before the |)
val Functions$Function2<String, String, String> sendsms= [ sms_text, sms_recipient |
		logInfo ("script", "The sendsms script is called")
		logInfo ("script", "First parameter =" + sms_text)	
		logInfo ("script", "Second parameter =" + sms_recipient)	
		true
]

So in my example, I try to pass 2 parameters (instead of one in the example).

When saving, I get:

2017-05-30 18:25:37.122 [INFO ] [el.core.internal.ModelRepositoryImpl] - Validation issues found in configuration model 'sendsms.script', using it anyway:
This expression is not allowed in this context, since it doesn't cause any side effects.
The value of the local variable sendsms is not used
2017-05-30 18:25:37.123 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model 'sendsms.script'

I use this rule to call the script:

rule "test"

when   
    Item  TEST_Trigger changed from OFF to ON
then
	logInfo("test","Test rule triggered")
	sendsms.apply("some text", "some recipient")
end

Which results in this error when executed:

2017-05-30 18:26:56.781 [INFO ] [eclipse.smarthome.model.script.Alarm] - Test rule triggered
2017-05-30 18:26:56.782 [ERROR] [.script.engine.ScriptExecutionThread] - Rule 'test': An error occured during the script execution: The name 'sendsms' cannot be resolved to an item or type.

So I’m stuck again…

Try this one:

import org.eclipse.xtext.xbase.lib.Functions

val org.eclipse.xtext.xbase.lib.Functions$Function2<String, String, Boolean> sendsms = [
	sms_text,
	sms_recipient |	
		logInfo ("script", "The sendsms script is called")
		logInfo ("script", "First parameter =" + sms_text)	
		logInfo ("script", "Second parameter =" + sms_recipient)	
		true
	]

rule "test"
when
	Item TEST_Trigger changed from OFF to ON
then
	logInfo("test","Test rule triggered")
	sendsms.apply("some text", "some recipient")
end

Since your return value is a Boolean you have to specify this in your Lambda.

Unfortunately,
I still get the same errors with your example:

2017-05-30 19:37:12.232 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model 'sendsms.script'
2017-05-30 19:37:12.596 [INFO ] [el.core.internal.ModelRepositoryImpl] - Validation issues found in configuration model 'sendsms.script', using it anyway:
This expression is not allowed in this context, since it doesn't cause any side effects.
The value of the local variable sendsms is not used
2017-05-30 19:37:12.597 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model 'sendsms.script'
2017-05-30 19:37:30.002 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model 'test.rules'
2017-05-30 19:37:30.557 [INFO ] [el.core.internal.ModelRepositoryImpl] - Loading model 'test.rules'
2017-05-30 19:39:12.955 [INFO ] [.eclipse.smarthome.model.script.test] - Test rule triggered
2017-05-30 19:39:12.955 [ERROR] [.script.engine.ScriptExecutionThread] - Rule 'test': An error occured during the script execution: The name 'sendsms' cannot be resolved to an item or type.

Maybe I need to activate something in my OH2 installation before scripts start to work? Or reboot?

Ok,
I’ve found another simple lambda example, so I tried this:

In sendsms.script:

import org.eclipse.xtext.xbase.lib.Functions

val org.eclipse.xtext.xbase.lib.Functions$Function1<String, Boolean> foo = [ s |	
		logInfo ("script", "The sendsms script is called")
		true
	]

My rules file:

    foo.apply ("bar")

I still have the same error message…

OMG!

I have totally missed your point of using a Lambda in a script and call it from a rule. My example was referring only to a rule :frowning:

EDIT:

I think, you can use some items to hold your parameter for the script.

sendsms.items:

String	sms_text
String	sms_recipient

sendsms.script:

logInfo ("script", "The sendsms script is called")
logInfo ("script", "First parameter =" + sms_text.state)	
logInfo ("script", "Second parameter =" + sms_recipient.state)	

and finally your rule:

rule "test"
when
	Item TEST_Trigger changed from OFF to ON
then
	logInfo("test","Test rule triggered")
	sms_text.postUpdate("some text")
	sms_recipient.postUpdate("some recipient")
	callScript("sendsms")
end

Lambdas and scripts are two different things.

A Script is a piece of code that lives in the scripts folder. One cannot pass arguments to a Script nor can one get a return value from a Script. I frankly find them not particularly useful.

Lambdas, on the other hand, are a variable. Lambdas must be defined in a .rules file and only rules that reside in the same file as the lambda can call the lambda.

You cannot call a lambda defined in a .script file from a .rules file.

Notice how @ptweety’s example is all in the same “file” as presented. That is not by accident.

Of course, if you wanted to pass arguments to a .script file, @ptweety’s second example would be the way to do it.

I personally prefer this approach:

1 Like

Hi both,

Thanks. I understand why my “script” wasn’t working. :grin: Well in any case thanks, since now I also fully understand lambda’s.

And indeed, since passing parameters is not possible (@ptweety: defining items and filling it with data is a good workaround), this makes scripts much more limited than I thought.

I’ll think I’ll follow (as stated in the design pattern) the approach where I create a rule “send sms” which is triggered as soon as a value is entered in item sms_text.

Well actually i still find scripts very useful, since in my case, i use a rule to execute a script every 5 minutes to read smartphone presence and send this value to MQTT broker. Then in items file i use mqtt and JSONPATH transformation to read the valıue and assign it to a switch which i can use .state to invoke some of my rules. OK it is one way but still very useful for me.
Btw if you are after smartphone notification for some events, you can still handle it with pushover or pushsafer bindings so you can get any notification you like in your smartphone just as simple as pushover(“some text”).

If you are using OH scripts (not to be confused with bash scripts or python scripts), why not have the script just populate the Item directly instead of going through MQTT?

Hi Erkan,

Thanks for the suggestion. I am aware of these possibilities. However, for “high priority alerts” (smoke detector stuff), I prefer a traditional text message (SMS), not relying on the 3G/4G connection of my phone. All other alerts can be sent via Pushsafer or similar.

Actually i use a bash script…

bash scripts are not the same thing as being referred to here.

http://docs.openhab.org/configuration/rules-dsl.html#scripts

Hi All

Im trying to populate string items with commands, which will be sent to a bash script

I cant see to get it to function, the command has “” around 0, which may be causing an issue. if I place +KDS_Command.state at the end of the executed command, it doesnt send :frowning:

I’m missing something? Thanks


rule "Put KDS into Standby"
when
        Item KDS_Power received command
then
        if(KDS_Power.state == ON){
             KDS_Command.postUpdate('Action Preamp/Product 2 SetStandby "0"')
             var result = executeCommandLine("sudo /etc/openhab2/scripts/linn.sh",5000)
        logInfo("linn", "results- " + result)
        }
        if(KDS_Power.state == OFF){
             KDS_Command.postUpdate('Action Preamp/Product 2 SetStandby "1"')
             var result = executeCommandLine("sudo /etc/openhab2/scripts/linn.sh",5000)
        logInfo("linn", "results- " + result)
        }
end

Your post really has nothing to do with this topic, so hopefully a moderator can split it to another topic. I am doing a lot of guesing at what you are saying, but I think what you are missing is that you will need to use the magical @@ to separate arguments for your script when using executeCommandLine. The state of KDS_Command is pretty funky… and your rule can be cleaned up a bit…

rule "Put KDS into Standby"
when
    Item KDS_Power received command
then
    val new_state = 'Action Preamp/Product 2 SetStandby "' + if (KDS_Power.state == ON) '0"' else '1"'
    KDS_Command.postUpdate(new_state)
    val result = executeCommandLine("sudo /etc/openhab2/scripts/linn.sh@@" + new_state, 5000)
    logInfo("linn", "results: {}", result)
end

Hi Scott, its about passing a parameter (held in a string) to script - it has everything to do with it?, right?

That rule doesnt work im afraid.

10:14:10.081 [WARN ] [del.core.internal.ModelRepositoryImpl] - Configuration model 'linn.rules' has errors, therefore ignoring it: [7,74]: missing ')' at '0'
[7,77]: mismatched input ')' expecting '}'
[11,2]: mismatched input '}' expecting 'end'

This OP is about using the ScriptExecution.callScript Action. You are using the Exec.executeCommandLine Action. Very different critters.

I’m still thinking in Jython… I updated my post… try that one :slightly_smiling_face:.

Ahhh! Wasnt aware that existed.

Cool, accepts it now! But unforunately doesnt work, the log doesnt populate with the results and theres no errors thrown which is odd. Ill have to keep digging. It could be the script…but i thought it would at least populate the KDS_Command string item

1 Like

Seems the rule is wrong, because KDS_Command isnt being updated. It still shows as 0

Don’t think that rule works Scott as you’ve defined it, if it did then it should have the right state. So i think the val command etc etc is not right.

if i go back to my old rule, tweaked

rule "Put KDS into Standby"
when
        Item KDS_Power received command
then
        if(KDS_Power.state == ON){
             KDS_Command.postUpdate('Action Preamp/Product 2 SetStandby "0"')
             var result = executeCommandLine("sudo /etc/openhab2/scripts/linn.sh@@" + KDS_Command.state,5000)
        logInfo("linn", "results- " + result)
        }
        if(KDS_Power.state == OFF){
             KDS_Command.postUpdate('Action Preamp/Product 2 SetStandby "1"')
             var result = executeCommandLine("sudo /etc/openhab2/scripts/linn.sh@@" + KDS_Command.state,5000)
        logInfo("linn", "results- " + result)
        }
end

Nada :frowning: