Exec Binding do not work

Hi,
can anyone please post an working example Thing/Item/sitemap for a simple switch which shall send an On/Off comand via Exec [command="curl … .
I spend hours trying different solutions, also with 2 separate things for the On and Off, but nothing worked as it should.

Why are such simpel things so complicated to implement?

Thanks, Holger

Hi, well, I found it rather easy…
I created a new exec thing in the Paper UI. I gave the thing a name and configured the command it should execute.
I set the interval to 0, so it’s executed only once. The other fields are the default.
Then, I created a link for the “Running” channel and defined my item in the conf file:

Switch Name <icon> (group)    { channel="exec:command:name-of-exec-thing:run" }

Define it in your sitemap, voila. When you trigger the switch the command is executed.

Christian

1 Like

Or just:

Things
Thing exec:command:licht_on [command="/opt/brematic/licht_sofa_on.sh, timeout=5]
Thing exec:command:licht_off [command="/opt/brematic/licht_sofa_off.sh, timeout=5]

Items
Switch licht_sofa_on {channel=“exec:command:licht_on:run”}
Switch licht_sofa_off {channel=“exec:command:licht_off:run”}

Rules
rule "Licht Sofa"
when
Item licht_sofa changed
then
if(licht_sofa.state == OFF){
licht_sofa_off.sendCommand(ON)
licht_sofa_on.postUpdate(OFF)
}
if(licht_sofa.state == ON){
licht_sofa_on.sendCommand(ON)
licht_sofa_off.postUpdate(OFF)
}
end

Is there no way to use a single Switch item?

Not with the 2.x version of the exec binding. If you want the old style use 1.x version

I’ve been investigating the code for the Exec 2.0 binding and there are definitely some quirky aspects to it. It seems like it should be possible to support a more straightforward switch behavior without extensive changes to the binding. For my investigation, I’m using the following thing definition:

Thing exec:command:switch_control [command="/tmp/switch_control.sh %2$s", interval=0, autorun=true]

The %2$s will be replaced with a value on the input channel. The “interval=0” specifier is an undocumented feature that disables periodic execution. The autorun option is “a boolean parameter to make the command execute immediately every time the state of the input channel has changed”.

My test item is:

String ExecSwitchTest {channel="exec:command:switch_control:input"}

The documentation says that the input channel is the “Input parameter to provide to the command”. Based on the description of the autorun configuration, I initially assumed this was driven by item state changes, since command events don’t actually represent an item change. However, the Exec binding only responds to command events for the input channel. After learning that, I tried sending a command to the item. Initially I had created a Switch item and sent ON/OFF commands. However, the code only responds to string commands and doesn’t attempt to convert non-string commands to strings like “ON” and “OFF”. After changing the item to a String and sending commands I was finally able to see my script executed with the command string as the argument.

In my opinion, there are some simple improvements that could be made to the binding.

  • Support other item types and convert states/commands to strings for command formatting.
  • Either make the input channel respond to state changes or fix the documentation.
  • Make a missing interval option mean “no periodic execution”

With these changes I think we may be able to support a Switch with a single thing and an item bound to the input channel. It’s not quite the same as the OH1 in/out specifications but it’s better than defining multiple items and using rules to implement the same behavior.

5 Likes

@kgoderis

Hi steve1,

very good, your solution works! Thanks very much.
Well defining the item as string and not as switch is really not the intuitive way one would go.
Maybe this can be improved for the release version.

Holger

1 Like

Some quick initial thoughts on this.

If we want to support other Item types, then we would have to create a new channel type per type of Item, since Channel Types have to be defined with an Item Type in mind. This would “pollute” a bit the channels and maybe more confusing after all. I reverted to the StringType as this is the most common denominator, and maybe the easiest one to convert to in Rules and Scripts. Conversion as you suggest is not really an option, but I will investigate how it can fit into the automatic conversion between Item Types that was introduced lately (smarthome/bundles/core/org.eclipse.smarthome.core.thing/src/main/java/org/eclipse/smarthome/core/thing/internal/ThingManager.java at 3ce6ba13cf330f7fe86336bbff7fdd289a1b6499 · eclipse-archived/smarthome · GitHub)

Make the binding do handleUpdate() is an option. I think that I only considered handleCommand() as that was the more logical approach, e.g send a Command, albeit through an external shell command/script. The reason the Autorun thing is there is to cope with those use case whereby you would have high-frequency execution due some Rule set up. I agree that the wording in the doc could rather be “a boolean parameter to make the command execute immediately every time a Command has been sent to the input channel”

A missing interval is something that is Ok with respect the current code base. If you do not specify it, then no periodic execution is scheduled in the scheduler.

K

Good point. I didn’t know that was a constraint but I agree that it wouldn’t be desirable to have a channel per item type. I see the ‘run’ channel is associated with a Switch item. Is it possible to pass the Switch command to the command formatter for that channel like you do for the input channel?

Having the input channel process String commands is fine with me if the documentation is clear about it.

@kgoderis, both the ‘input’ and ‘run’ channels can trigger execution of an Exec things script (I’ll refer to the thing’s command as a script to avoid confusion with an item command). With the following definitions:

Thing exec:command:switch_control [command="/tmp/switch_control.sh %2$s", interval=0, autorun=true]

String ExecInput {channel="exec:command:switch_control:input"}
Switch ExecRun   {channel="exec:command:switch_control:run"}

If send a command string, like “TEST”, to the ExecInput item, I see the script executed with the command string as an argument.

If I then send an ON command to the run channel, I again see the script executed with “TEST” as the argument. If I send an OFF command to the run channel, then nothing happens. Also, the run channel state is changed by the binding to indicate if the script is running or not.

What is the intended interaction between the run and input channels?

‘run’ has to be used to trigger the execution of the thing’s command using the then actual value (.e.g state) of the input channel. You can thus set the ‘input’ once, but execute it multiple times by sending ON to the ‘run’ channel. Next to that, the ‘run’ channel is an indicator that the thing’s command is running, switching its state to OFF when the thing’s command has finished running

‘input’ is a means to set the input for the Thing’s command, using the %2$s format. It will not trigger the execution of the thing’s command, unless autorun=true, in which case the execution is triggered if the value send to the input channel is different from a previously set/send value

Thanks. That’s what I thought, but I wanted to be sure. Given a common use case will be using the exec binding with a switch, what do you think about adding a switch channel? It would similar to input with autorun=true but would pass its new state as the command line argument. It could update the run channel state in the same way as the input channel. However, a run command would still only work with input. That might be confusing. Maybe the running status should be a separate status channel instead of combining both the triggering and status into one channel?

If send a command string, like “TEST”, to the ExecInput item, I see the script executed with the command string as an argument.

It was not my experience, until i mapped something into the ‘run’ channel i did not see script running at all. I tried to map ‘run’ only, then ‘input’ only - no way, it only runs shell script if both ‘run’ and ‘input’ are mapped to something, in my case it is a same item - switch. mapping to ‘String’ did not run the script either.

All this is totally counter intuitive. How was this contraption supposed to implement a simple execution of a script when we turn a switch ON and OFF? Script has to run upon both conditions, not only when it is getting ‘ON’ command.

All this makes no sense at all.

The code has changed over the last month or two so you might see different behavior if you have an installation from around that time or before.

The latest code will trigger execution from the input channel if autorun=true and the item is a String item. No need to bind the run channel in that case.

I agree that the switch use case should have direct support.

ok, I got it almost working.

So, thing had to be defined as this:
Thing exec:command:pluglight [command="/opt/openhab2/conf/scripts/off.sh %2$s", interval=0, timeout=5, autorun=true]

Item is defined as this:
String PlugOne “Lamp One” {channel=“exec:command:pluglight:input”}

adding autorun changed the behavior - now in the basic UI i flip the mapping from on to OFF and it run associated script every time and it passes OFF and ON every time. I checked that - it is easy - here is off.sh script:

#!/bin/sh
echo deleting on ;
rm /opt/openhab2/conf/scripts/testfiles/on ;
echo creating off ;
touch /opt/openhab2/conf/scripts/testfiles/off ;
echo 1 >> /opt/openhab2/conf/scripts/testfiles/off
echo $1 >> /opt/openhab2/conf/scripts/testfiles/off
echo 2 >> /opt/openhab2/conf/scripts/testfiles/off
echo $2 >> /opt/openhab2/conf/scripts/testfiles/off
echo 3 >> /opt/openhab2/conf/scripts/testfiles/off
echo $3 >> /opt/openhab2/conf/scripts/testfiles/off

I am now trying to fix other scripts and check what parameter value gets passed. my old scripts needed only lower case ‘on’ and ‘off’ - this new thing passes uppercase. but it seems to be getting there.

I sort of got it to turn on and off now. But i am still at a complete loss how I am supposed to marry status check with this switch object. Here is a working config i have now for the TPLink hs200:

Things file:
Thing exec:command:pluglight [command=“/opt/openhab2/conf/scripts/hs100.sh 192.168.10.42 9999 %2$s”, interval=0, timeout=5, autorun=true]
Thing exec:command:pluglightcheck [command=“/opt/openhab2/conf/scripts/hs100.sh 192.168.10.42 9999 check”, interval=1, timeout=5]

Items:
String PlugOne “Lamp One” {channel=“exec:command:pluglight:input”}

Sitemap:
Switch item=PlugOne mappings=[“on”=“on”,“off”=“off”]

So all this above allows to go into basicUI, find ‘Lamp One’ in there and toggle it off and on and it turns off an on fine, very good. Half way there.
Now, what should be done to update status of ‘Lamp One’ in the interface using this other thing ‘exec:command:pluglightcheck’ when lamp switch is flipped by hand?


OK, i solved that too.

items:
String PlugOne “Lamp One” {channel=“exec:command:pluglight:input”}
String PlugOneState “Plug One Status” {channel=“exec:command:pluglightcheck:output”}

things:
Thing exec:command:pluglight [command=“/opt/openhab2/conf/scripts/hs100.sh 192.168.10.42 9999 %2$s”, interval=0, timeout=5, autorun=true]
Thing exec:command:pluglightcheck [command=“/opt/openhab2/conf/scripts/hs100.sh 192.168.10.42 9999 check”, interval=1, timeout=5]

sitemap:
Switch item=PlugOne mappings=[“ON”=“ON”,“OFF”=“OFF”]
//Text item=PlugOneState label=“Plug One State [%s]”

rule:
rule “Plug One”
when
Item PlugOneState changed from ON to OFF
then
postUpdate(PlugOne,“OFF”)
logInfo(“Network”, "Switching Plug Off: " )
end

rule “Plug Two”
when
Item PlugOneState changed from OFF to ON
then
postUpdate(PlugOne,“ON”)
logInfo(“Network”, "Switched Plug On: " )
end

This way it flips PlugOne in the sitemap according to the status. All works, switch switches, all good.

This solution has issues. When you flip switch by hand - say, it was OFF and you set it to ON by hand - it updates status on the screen correctly, so interface shows ‘ON’. When you press ‘OFF’ on the screen - this thing DOES NOT execute the script!

I think it presumes that actual channel is still at ‘OFF’ so there is no change and it does not run anything. If you then flip switch to ON and then to OFF - in the interface - only then it works. It is unacceptable, as with Alexa voice command it is infuriating - you tell it to turn it off and it does not do it.

How can the input channel status be updated? String associated with it does not seem to do anything.

@Paul_Atkin, have you tried binding both the input channel of the thing that controls the lights and the output channel of the status check script to the same item (similar to Karel’s earlier example in this topic)?

A command sent to the item will be processed by the input channel (assuming autorun=true) and will trigger the control script to run. The result of the periodically polled check script should be written to the item state via the output channel.

@kgoderis, since the ‘autorun’ option only applies to the input channel, wouldn’t it be better to support that type of configuration? For example, I have seen this in the documentation…

Contact Garage { channel="zwave:21:command=sensor_binary,respond_to_basic=true" }

Applied to Exec…

Thing exec:command:switch_control [command="/tmp/switch.sh %2$s"]
Thing exec:command:switch_monitor [command="/tmp/switch.sh check"]

String ExecInput { channel="exec:command:switch_control:input,autorun", channel="exec:command:switch_monitor:output,interval=1" }

(warning: there may be syntax errors in these examples since I don’t have access to my OH system at the moment.)

Does not work.

with ‘interval=1’ added it generates error like shown at the end of the response. if ‘interval’ removed error not shown, but in both cases system behaves as this: you flip switch manually, it changes on the screen. if you click on the interface to flip it - it jumps, say, from ‘ON’ to ‘OFF’ as instructed, then jumps back to ‘ON’, actual switch does not change.
so it still does not work. i suspect it is due to the value of “exec:command:pluglight:input” that gets stuck to what was set by the interface and not updated by the actual manual change of the device.

Item is defined as this:

String PlugOne “Lamp One” [ “Switchable” ] {channel=“exec:command:pluglight:input”, channel=“exec:command:pluglightcheck:output”}

2017-01-05 14:29:01.083 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model 'My_House.items’
2017-01-05 14:29:01.092 [ERROR] [el.item.internal.GenericItemProvider] - Binding configuration of type ‘channel’ of item ‘PlugOne’ could not be parsed correctly.
org.eclipse.smarthome.model.item.BindingConfigParseException: UID must have at least 4 segments.
at org.eclipse.smarthome.model.thing.internal.GenericItemChannelLinkProvider.createItemChannelLink(GenericItemChannelLinkProvider.java:82)[131:org.eclipse.smarthome.model.thing:0.9.0.201612221226]
at org.eclipse.smarthome.model.thing.internal.GenericItemChannelLinkProvider.processBindingConfiguration(GenericItemChannelLinkProvider.java:72)[131:org.eclipse.smarthome.model.thing:0.9.0.201612221226]
at org.eclipse.smarthome.model.item.internal.GenericItemProvider.internalDispatchBindings(GenericItemProvider.java:312)[121:org.eclipse.smarthome.model.item:0.9.0.201612221226]
at org.eclipse.smarthome.model.item.internal.GenericItemProvider.internalDispatchBindings(GenericItemProvider.java:284)[121:org.eclipse.smarthome.model.item:0.9.0.201612221226]
at org.eclipse.smarthome.model.item.internal.GenericItemProvider.processBindingConfigsFromModel(GenericItemProvider.java:167)[121:org.eclipse.smarthome.model.item:0.9.0.201612221226]
at org.eclipse.smarthome.model.item.internal.GenericItemProvider.modelChanged(GenericItemProvider.java:347)[121:org.eclipse.smarthome.model.item:0.9.0.201612221226]
at org.eclipse.smarthome.model.core.internal.ModelRepositoryImpl.notifyListeners(ModelRepositoryImpl.java:207)[120:org.eclipse.smarthome.model.core:0.9.0.201612221226]
at org.eclipse.smarthome.model.core.internal.ModelRepositoryImpl.addOrRefreshModel(ModelRepositoryImpl.java:120)[120:org.eclipse.smarthome.model.core:0.9.0.201612221226]
at org.eclipse.smarthome.model.core.internal.folder.FolderObserver.checkFile(FolderObserver.java:270)[120:org.eclipse.smarthome.model.core:0.9.0.201612221226]
at org.eclipse.smarthome.model.core.internal.folder.FolderObserver.access$1(FolderObserver.java:264)[120:org.eclipse.smarthome.model.core:0.9.0.201612221226]
at org.eclipse.smarthome.model.core.internal.folder.FolderObserver$WatchQueueReader.processWatchEvent(FolderObserver.java:145)[120:org.eclipse.smarthome.model.core:0.9.0.201612221226]
at org.eclipse.smarthome.core.service.AbstractWatchQueueReader.run(AbstractWatchQueueReader.java:122)[96:org.eclipse.smarthome.core:0.9.0.201612221226]
at java.lang.Thread.run(Thread.java:745)[:1.8.0_112]