Exec Binding 2.4.0 - Change gpio pin of a remote Raspberry (bash script and SSH) - Openhabian

1) Introduction
I’m a beginner so I found some problem to understand Exec Binding. In my opinion the guide isn’t clear for this addon. I think there should be in exec binding one command to execute an external program, the response of the program and optional another external command to check the “state” of the thing.
Please sorry for my english

2) Purpose of tutorial
This is a step by step tutorial to change a GPIO value in a remote raspberry pi with openhab using Exec binding 2.x. The binding will run a bash script in OpenHab linux server that change gpio value in another raspberry pi. I have openhabian in a raspberry pi 4. In my example GPIO pin 21,22,23,25 command a 4 channel-relay (GPIO pin 21 command one relay, GPIO pin 22 command another relay…ecc)

3) Preparation

Remote Raspberry pi
Access to the remote raspberry pi where you want to change pin and install wiring pi. To check if it works you can change the value of the GPIO pin using.

gpio write 22 1
gpio write 22 0

User openhab has to access to the remote raspberry. Change user@hostname (e.g. root@192.168.1.100) with the one of remote raspberry and access with password. This will copy the public key to the remote system

sudo -u openhab ssh-keygen -t rsa
sudo -u openhab ssh-copy-id -i /var/lib/openhab2/.ssh/id_rsa.pub user@hostname

Check if openhab user can access to the remote system

sudo -u openhab ssh user@hostname

create a folder for Scripts (I create /home/openhabian/Script) and a file RemoteGpioSwitch.sh. Change in the file the word “user” with the right username (e.g. user@$2 → root@$2)

#!/bin/bash
## USE RemoteGpioSwitch.sh GPIO_PIN IP_SSH ON_OFF

  # If I have ON in input I put on the GPIO of the relay else I put off the gpio pin of the relay
  if [[ "$3" = "ON" ]] || [[ "$3" = "On" ]] || [[ "$3" = "on" ]]   ; then
     Comando=$(ssh user@$2 "/usr/local/bin/gpio write $1 1")
 #    echo $Comando > /home/openhabian/Script/onoff.txt
     echo OFF
  else

  #   gpio write $1 1
     Comando=$(ssh user@$2 "/usr/local/bin/gpio write $1 0")
#     echo $Comando > /home/openhabian/Script/onoff.txt 
     echo ON
  fi

Give permission to the script (I use chmod 777 to give all the permissions to the file, remember that user openhab have to use this, when you access in SSH your user is openhabian)

Now you can test the script to see if it works like you want, arguments are:
GPIO_PIN->Pin of remote raspberry pi
IP_SSH->IP of remote raspberry pi
ON_OFF-> ON or OFF
e.g.

sudo -u openhab /home/openhabian/Script/RemoteGpioSwitch.sh 22 192.168.1.100 ON

Openhabian Paper UI
Install exec 2.x binding from Add-ons->bindings


Install RegEx transformation from binding from Add-ons->Transformations. The transformation is used by default in the binding if no other is specified(I read it somewhere in the forum, but I can’t remember where)

Openhabian SSH
Now we start with openhab configurations.

nano $OPENHAB_CONF/sitemaps/presecontrollate.sitemap

sitemap presecontrollate label="Powerplug"
{
        Frame label="Powerplug"
        {
          Switch item=Sala_Power1_1 label="Stereo Sala"
          Switch item=Sala_Power1_2 label="TV"
          Switch item=Sala_Power1_3 label="Lamp"
          Switch item=Sala_Power1_4 label="Vuota"
        }
   
}

nano $OPENHAB_CONF/things/exec.things

Thing exec:command:Sala_Power1_1_Send "Sala_Power1_1" [
        command="/home/openhabian/Script/RemoteGpioSwitch.sh %2$s",
        interval=0,
        autorun=true]

Thing exec:command:Sala_Power1_2_Send "Sala_Power1_2" [
        command="/home/openhabian/Script/RemoteGpioSwitch.sh %2$s",
        interval=0,
        autorun=true]

Thing exec:command:Sala_Power1_3_Send "Sala_Power1_3" [
        command="/home/openhabian/Script/RemoteGpioSwitch.sh %2$s",
        interval=0,
        autorun=true]

Thing exec:command:Sala_Power1_4_Send "Sala_Power1_4" [
        command="/home/openhabian/Script/RemoteGpioSwitch.sh %2$s",
        interval=0,
        autorun=true]

nano $OPENHAB_CONF/items/exec.items

// Presa controllata Power1 - Sala - Raspberry

// Presa 1 - Stereo Sala
Switch Sala_Power1_1 "Stereo Sala" <poweroutlet> {alexa="PowerController.powerState"}
Switch Sala_Power1_1_Send "Running" { channel="exec:command:Sala_Power1_1_Send:run" }
String Sala_Power1_1_Send_Args "Input" { channel="exec:command:Sala_Power1_1_Send:input"}
String Sala_Power1_1_Send_Out "State" { channel="exec:command:Sala_Power1_1_Send:output"}
// Presa 2 - TV
Switch Sala_Power1_2 "TV" <poweroutlet> {alexa="PowerController.powerState"}
Switch Sala_Power1_2_Send "Running" { channel="exec:command:Sala_Power1_2_Send:run" }
String Sala_Power1_2_Send_Args "Input" { channel="exec:command:Sala_Power1_2_Send:input"}
String Sala_Power1_2_Send_Out "State" { channel="exec:command:Sala_Power1_2_Send:output" }
// Presa 3 -  Palle di "Natale"
Switch Sala_Power1_3 "Lamp" <poweroutlet> {alexa="PowerController.powerState"}
Switch Sala_Power1_3_Send "Running" { channel="exec:command:Sala_Power1_3_Send:run" }
String Sala_Power1_3_Send_Args "Input" { channel="exec:command:Sala_Power1_3_Send:input"}
String Sala_Power1_3_Send_Out "State" { channel="exec:command:Sala_Power1_3_Send:output" }

// Presa 4 -  Presa vuota
Switch Sala_Power1_4 "vuota sala" <poweroutlet> {alexa="PowerController.powerState"}
Switch Sala_Power1_4_Send "Running" { channel="exec:command:Sala_Power1_4_Send:run" }
String Sala_Power1_4_Send_Args "Input" { channel="exec:command:Sala_Power1_4_Send:input"}
String Sala_Power1_4_Send_Out "State" { channel="exec:command:Sala_Power1_4_Send:output" }

In the items there is also Alexa integration. This is the part of code for Alexa: {alexa=“PowerController.powerState”}, if you don’t have it remove only the part between{ }
“Lamp” in the example is part of the Alexa voice command. You can choose the label that you want

Switch Sala_Power1_3 "Lamp" <poweroutlet> {alexa="PowerController.powerState"}

Then we have to define rules.
nano $OPENHAB_CONF/items/exec.rules

import org.eclipse.smarthome.model.script.ScriptServiceUtil
//______________________________________________________Presa controllata Power1 - Sala - Raspberry_____________________________

//----------------------------------------------------- Presa 1 - Stereo Sala
rule "Power1_1 Stereo"
  when
    Item Sala_Power1_1 received command
  then
     if(receivedCommand == ON){
        Sala_Power1_1_Send_Args.sendCommand("21 192.168.1.21 OFF")
     }else{
       Sala_Power1_1_Send_Args.sendCommand("21 192.168.1.21 ON")
     }
end
// ---------------------------------------------------- Presa 2 - TV
rule "Power1_2 TV"
  when
    Item Sala_Power1_2 received command
  then
     if(receivedCommand == ON){
        Sala_Power1_2_Send_Args.sendCommand("22 192.168.1.21 OFF")
     }else{
        Sala_Power1_2_Send_Args.sendCommand("22 192.168.1.21 ON")
     }
end
//----------------------------------------------------- Presa 3 -  LAMP
rule "Power1_3 Lamp"
  when
    Item Sala_Power1_3 received command
  then
     if(receivedCommand == ON){
        Sala_Power1_3_Send_Args.sendCommand("23 192.168.1.21 OFF")
     }
else{
       Sala_Power1_3_Send_Args.sendCommand("23 192.168.1.21 ON")
     }
end
//----------------------------------------------------- Presa 4 -  Presa vuota
rule "Power1_4 Vuota"
  when
    Item Sala_Power1_4 received command
  then
     if(receivedCommand == ON){
        Sala_Power1_4_Send_Args.sendCommand("25 192.168.1.21 OFF")
     }else{
       Sala_Power1_4_Send_Args.sendCommand("25 192.168.1.21 ON")
     }
end


//To see log give this command in SSH
//tail -f /var/log/openhab2/openhab.log -f /var/log/openhab2/events.log
// This rule is for logging purpose.
rule "report exec finished"
when
   Item Sala_Power1_1_Send changed to OFF or
   Item Sala_Power1_2_Send changed to OFF or
   Item Sala_Power1_3_Send changed to OFF or
   Item Sala_Power1_4_Send changed to OFF
      // you could use Group trigger with Member of here instead
then
      // find linked item
   val targetName = triggeringItem.name + "_Out"
   val myStatus = ScriptServiceUtil.getItemRegistry.getItem(targetName)
      // do message
   logInfo("Power_Plug", "Results are: \n" + targetName + " " + myStatus.state )
end

Now you can control from Basic UI the GPIO pins

Sources

Thanks for an improvement in the tutorial code
rossko57 - OpenHAB logging items status (removed while loop in items rule)

1 Like

There is a race condition there. The rule has only just sent the arguments to the Exec binding. The rule does not stop and wait for anything to happen. The binding takes time to work and then to set its RUN channel to ON, to show the script is running.
If you are unlucky, the while() test will find it still OFF at the first test.

Rather than tie up rule resources with sleep, there is another approach using a separate rule. Here, you only want to log a message and so one rule can do all pins by taking advantage of your useful Item naming scheme.

//import at top of rulesfile
import org.eclipse.smarthome.model.script.ScriptServiceUtil

rule "report exec finished"
when
   Sala_Power1_1_Send changed to OFF or
   Sala_Power1_2_Send changed to OFF or
   Sala_Power1_3_Send changed to OFF or
   Sala_Power1_4_Send changed to OFF
      // you could use Group trigger with Member of here instead
then
      // find linked item
   val targetName = triggeringItem.name + "_Out"
   val myStatus = ScriptServiceUtil.getItemRegistry.getItem(targetName)
      // do message
   logInfo("Power_Plug", "Results are: \n" + targetName + " " + myStatus.state )
end

EDIT typo in that rule, omitted the important Item keyword of the triggers.

Thank you rossko57 for your suggest. Sorry for late reply but this week I hadn’t free time after work to play with openHAB.
This seems a very good solution, you can use item names as variables.
I set Item name “Sala_Power1_1_Stereo” to “Sala_Power1_1” (in every file items,things,sitemaps,rules) and logging are ok using your code

2019-12-07 17:47:31.337 [ome.event.ItemCommandEvent] - Item 'Sala_Power1_2' received command ON
2019-12-07 17:47:31.356 [vent.ItemStateChangedEvent] - Sala_Power1_2 changed from OFF to ON
2019-12-07 17:47:42.949 [ome.event.ItemCommandEvent] - Item 'Sala_Power1_2' received command OFF
2019-12-07 17:47:42.965 [vent.ItemStateChangedEvent] - Sala_Power1_2 changed from ON to OFF
2019-12-07 17:47:43.130 [ome.event.ItemCommandEvent] - Item 'Sala_Power1_2' received command ON
2019-12-07 17:47:43.139 [vent.ItemStateChangedEvent] - Sala_Power1_2 changed from OFF to ON
2019-12-07 17:47:43.896 [ome.event.ItemCommandEvent] - Item 'Sala_Power1_2' received command OFF
2019-12-07 17:47:43.906 [vent.ItemStateChangedEvent] - Sala_Power1_2 changed from ON to OFF

but now the rules with

Item "Item_Name" received command

aren’t triggered. Do you have any suggest?

What rules? Show please.

Not valid syntax - no quote marks wanted there.

Sorry, there aren’t quote. I remove only the while condition, but it continue works.
This is one of the rule

rule "Power1_1 Stereo"
  when
    Item Sala_Power1_1 received command
  then
     if(receivedCommand == ON){
        Sala_Power1_1_Send_Args.sendCommand("21 192.168.1.21 OFF")
     }else{
       Sala_Power1_1_Send_Args.sendCommand("21 192.168.1.21 ON")
     }
end

After I add rule “report exec finished” it stop working
Only logs (logInfo) are ok. I can’t understand why

Have you looked in openhab.log to see if your rule file is correctly loaded?

You are right
There’s a sintax problem in the rule.

==> /var/log/openhab2/openhab.log <==
2019-12-09 15:29:52.229 [WARN ] [el.core.internal.ModelRepositoryImpl] - Configuration model 'exec.rules' has errors, therefore ignoring it: [76,4]: no viable alternative at input 'Sala_Power1_1_Send'
[77,4]: no viable alternative at input 'Sala_Power1_2_Send'
[78,4]: no viable alternative at input 'Sala_Power1_3_Send'
[79,4]: no viable alternative at input 'Sala_Power1_4_Send'

of course it needs to be

when 
   Item Sala_Power1_1_Send changed to OFF or
   ... etc

It really pays to use VSCode editor for syntax checking

It works, I will update the tutorial with the changes as soon as possible. This is a better solution for the logging. It works very well.

I was thinking to put another rule to check GPIO remote status but I’m not sure if it could be useful.
This can be done with another scheduled bash script (e.g. every minute) but I think that maybe to generate less network traffic I could check GPIO pin status on remote Raspberry and send MQTT message only when GPIO status changes

1 Like