Execute script using a switch

Hello openHAB community!
I’m an engineer but unfortunately not an IT engineer, so I hope my questions will not sound too silly :slight_smile:
Here the full story: I’d like to run a command by switching on a simple switch and, guess what, I’ve been struggling for three days unsuccessfully.
My configuration is as follows:

  • Raspberry pi4 to which I access through VNC --> works fine!
  • openHAB installed through apt-get --> works fine!
  • Sitemap looks as follows:
sitemap simple_switch label="Switch_to_run_script"
{
    Switch item=test_switch label="Test switch"
}
  • Items look as follows:
Group Test_group "Test group"
Switch test_switch "Test switch" (Test_group)
  • Rules look as follows:
rule "test switch ON OFF"
when Item test_switch changed
then
 if (test_switch.state == ON)
  executeCommandLine("sh /home/pi/Desktop/test_scripts/test_script.sh")
 else 
  executeCommandLine("sh /home/pi/Desktop/test_scripts/test_script.sh")
end
  • the script I’d like to execute (just open geany) looks as follows:
#!/bin/sh
geany

What I already did:

  • gave all users the right to execute the script with chmod
  • ran the script from a shell with sudo -u openhab test_script.sh
  • checked the openhab log: no errors
2020-04-19 12:08:45.875 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'sh /home/pi/Desktop/test_scripts/test_script.sh'
2020-04-19 12:08:48.470 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'sh /home/pi/Desktop/test_scripts/test_script.sh'
  • changed the header of the script by switching through bash, sh etc.
  • if I run the command
sudo visudo -f /etc/sudoers.d/010_pi-nopasswd

the result is

pi ALL=(ALL) NOPASSWD: ALL
openhab ALL=(ALL) NOPASSWD: ALL
  • replaced space with @@
  • changed the command line in the rule by removing sh

I hope you can help me sorting this issue!
Thanks in advance for your support!

test_switch is an Item, a complex object with name, type, icon, all kinds of properties. You’d usually be interested in its state.property.
if (test_switch.state == ON)

Hi rossko!
That was a typo in the post: original .items file looks correct. I’m really puzzled…

We can only work with what you give us. Now the game has been changed, so try …

var results
if (test_switch.state == ON)
  results = executeCommandLine("sh /home/pi/Desktop/test_scripts/test_script.sh")
else 
  results = executeCommandLine("sh /home/pi/Desktop/test_scripts/test_script.sh")
logInfo("test", "exec result " + results)

Yes, that was my bad! Apologies!
I tried what you suggested and the log says:

2020-04-19 13:17:32.979 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'sudo /home/pi/Desktop/test_scripts/test_script.sh'
2020-04-19 13:17:32.982 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'test switch ON OFF': An error occurred during the script execution: Couldn't invoke 'assignValueTo' for feature JvmVoid:  (eProxyURI: simple_switch.rules#|::0.2.0.2.0.0.1::0::/1)
2020-04-19 13:17:35.865 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'sudo /home/pi/Desktop/test_scripts/test_script.sh'
2020-04-19 13:17:35.868 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'test switch ON OFF': An error occurred during the script execution: Couldn't invoke 'assignValueTo' for feature JvmVoid:  (eProxyURI: simple_switch.rules#|::0.2.0.2.0.0.2::0::/1)

I suppose we should give the results variable some form first

var results = "blank"

Now the result:

2020-04-19 13:27:16.698 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'sudo /home/pi/Desktop/test_scripts/test_script.sh'
2020-04-19 13:27:16.714 [INFO ] [.eclipse.smarthome.model.script.test] - exec result null
2020-04-19 13:27:19.241 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'sudo /home/pi/Desktop/test_scripts/test_script.sh'
2020-04-19 13:27:19.254 [INFO ] [.eclipse.smarthome.model.script.test] - exec result null

Looks good. What are you expecting the script to do?

The script is supposed to open geany, just a text editor

Ah, like spawning some new independent process? I’m not sure if you can from there.

That’s a good point actually! Is the Exec binding the right thing to do in a case like this? (spawning a new process?)
As an info, I tested in a windows environment (starting notepad.exe in a batch file) and it worked.

Binding is not going to be any different.

I know little about *nix-y environments, but suspect this is to do with the command line not running in a shell.

Thanks for your hints! I hope Mr. @rlkoshak will stumble into this post :smiley:

In my first post I tried to be as simple as possible, but what I need to do in reality is to control a relay board connected to my RPi 4 (wired with i2c).
Now, I have a few simple python codes to control the status of each relay on the board and they work perfectly if I execute them from a shell. The problem is how to make openHAB execute these scripts.

  • I tried the original .py files with ‘executeCommandLine’ but no success.
  • I tried to create executable .sh scripts (which is what I described above) and use again ‘executeCommandLine’ but no success.
  • I even tried a native i2c binding but I believe RPi4 is not supported yet
  • After extensive search I think I could be using MQTT, but I really have no clue about how it works.

Has anyone had similar experiences?

Thanks to you all!

Similar experiences -

You can’t do that, or at least you can’t do that easily. It’s a long discussion I won’t go into here beyond:

  • You are logged in as a normal user (I’ll assume it’s user pi). This user “owns” the X-Window session
  • openHAB is running as user openhab
  • In order for openhab to open a GUI based app in the X-Windows session owned by pi there is a whole host of settings and permissions that need to be given to openhab. And even then it may not work because, as rossko57 indicated, executeCommandLine doesn’t run in a shell so it may not have permission.

tl;dr - you can’t open GUI based nor interactive stuff from openHAB without a whole heck of a lot of work.

If you just want to test use echo 'Hello world!'.

Don’t use sudo unless you really have to. If you do have to, please only configure the openhab user to be allowed to use only those commands it needs to run as sudo. Make sure to set it with NOPASSWD as there will be no way to enter a password. If all you need it permission to access the hardware, often the better approach is to add the openhab user to the right group (e.g. adding it to the dialout group so it can read/write to USB serial devices.

As what user? As mentioned above, openHAB runs as a restricted users named openhab. When you log in you are running as an unrestricted user, probably named pi. Every user has a unique set of permissions to do various things.

To get an idea of how a command will execute as the openhab user you can use sudo -u.

sudo -u openhab <command goes here>

This isn’t full proof as, as already mentioned, when openHAB runs it there is no shell.

Hi Rich!
Thanks for your detailed explanation! In fact, after a sleepless night, I was able to run the python script without having to compile it as an executable bash file.
What helped me to understand where the problem was, was the command

sudo -u openhab <python my_script.py>

I realized that the above command failed because the script does access i2c (I have to control a relay board wired to i2c bus) and that user openhab was simply not allowed to read that file. I added openhab to the i2c user and it magically worked.
Since you are here :slight_smile: I’ve got a question for you: is there any chance we can control the i2c bus using a native binding? I know such add-on exists, but I was unsuccessful when I tried to use it, perhaps because Pi4J does not support (yet) RPi4.
Would you have a very basic example of a combination item/rule for a switch that activates and deactivates an output on a i2c board?

Is it possible? I don’t see why not. But as with any binding it requires a developer to volunteer to write one. I don’t know anything about an existing I2C binding but I suspect, if you were unsuccessful before you added openhab to the i2c group, perhaps that was why it didn’t work and it’s worth giving the binding another try.

A binding will not be able to solve operating system enforced permission problems. The openhab user would need permission to read/write to the I2C file in any case.

Once you get to Items and Rules it’s all the same. That’s the power of openHAB and the reason why Items exist. Whether the Item is linked to a Zwave outlet, a GPIO pin, a I2C relay, or some binary control on a web server somewhere, interacting with the device from the sitemap or Rules is the same.

MySwitch.sendCommand(ON)

So any Rule that includes a Switch would work. The question you’ve not answered is “in response to what event do you want to turn ON or OFF the Switch?” Rules are event based. An event happens and a Rule runs to respond to that event, for example sending a command to a Switch Item.

The add-on I was referring to is the following:

There it’s clearly stated that this binding needs Pi4j, which can’t be used on a RPi4. And yes, I tried to use it after I added openhab to the i2c group but I got all sort of erros in the log.
By the way, the example in the documentation page contains the followin rule, which apparently has a syntax error:
living_room_led_switch.sendCommand(living_room_led_switch.state != ON ? ON : OFF)
In the log there was an error where the colon is.
What’s the meaning of the symbols !=, ? and : in this rule?

Reading the docs, this binding is specifically for the MCP23017 I/O expander. I doubt it would work with I2C devices unless they are connected through an MCP23017 chip.

If you do have your relays attached through such a chip, than the instructions say you need to add the openhab user to both the i2c and the gpio groups. Have you added it to the gpio group too?

The instructions also say you need to install wiringPi as well as Pi4J. IIRC wiringPi has been deprecated in raspbian so I would double check to see if it’s present. But, the Pi4j library does not list the RPi4 as supported and we have no control over that.

That is incorrect syntax for Rules DSL. I’ve submitted a PR to correct it.

That is a JavaScript ternary operator and it means, in English “If libing_room_led_switch.state is not ON then ON else OFF”. The whole line essentially means “sendCommand ON to living_room_led_switch if living_room_led_switch is not ON, otherwise sendCommand OFF.”

The proper syntax for that line is

living_room_led_switch.sendCommand(if(living_room_led_switch.state != ON) ON else OFF)