[SOLVED] Exec binding - getting old results

I’m a newbie to openhab and I’m trying to execute the same python script with different parameters to get different values:

  • python /home/openhabian/python/coop.py -g temp will print value between 20.5 and 30.5
  • python /home/openhabian/python/coop.py -g light will print value between 100 and 110

the script itself has rights to execute for everyone, works fine and prints out just the value and nothing else.

.items :

Number LightLevel "Light Level [%.1f]"
Number Temperature "Tempereture: [%.1f °C]" <temperature>

// state of the execution, is running or finished
Switch CC_command {channel="exec:command:coopPythonScript:run"}
// Arguments to be placed for '%2$s' in command line
String CC_command_Args {channel="exec:command:coopPythonScript:input"}
// Output of command line execution 
String CC_command_out {channel="exec:command:coopPythonScript:output"}

.rules :

rule "Coop temperature update"
      Time cron "0 0/1 * * * ?"
      logInfo( "coop.rules", "Temperature update..." )

      CC_command_Args.sendCommand("-g temp")
      // wait for the command to complete
      // State will be NULL if not used before or ON while command is executed
      while( CC_command.state != OFF ){
            Thread::sleep( 500 )

      // run script
      CC_command.sendCommand( ON )
      while( CC_command.state != OFF ){ //wait until script finishes?
            Thread::sleep( 500 )
      logInfo( "coop.py", "Temperature result:" + CC_command_out.state )
      Temperature.postUpdate(  Float::parseFloat( CC_command_out.state.toString ) as Number  );

rule "Coop light level update"
      Time cron "30 0/1 * * * ?"
      logInfo( "coop.rules", "Light level update..." )
      CC_command_Args.sendCommand("-g light")
      // wait for the command to complete
      // State will be NULL if not used before or ON while command is executed
      while( CC_command.state != OFF ){
            Thread::sleep( 500 )

      // run script
      CC_command.sendCommand( ON )
      while( CC_command.state != OFF ){ //wait until script finishes?
            Thread::sleep( 500 )
      logInfo( "coop.py", "Light level result:" + CC_command_out.state )
      LightLevel.postUpdate(  Float::parseFloat( CC_command_out.state.toString ) as Number  );


.sitemap :

sitemap coop label="MS-SmartCoop"
	Frame label="Chicken coop"{
		Text item=Temperature
		Text item=LightLevel

.things :

Thing exec:command:coopPythonScript [ command="python /home/openhabian/python/coop.py %2$s", interval=0, autorun=false ]

example log:

2018-10-30 07:09:00.052 [INFO ] [se.smarthome.model.script.coop.rules] - Temperature update...

==> /var/log/openhab2/events.log <==

2018-10-30 07:09:00.096 [ome.event.ItemCommandEvent] - Item 'CC_command_Args' received command -g temp

2018-10-30 07:09:00.227 [vent.ItemStateChangedEvent] - CC_command_Args changed from -g light to -g temp

2018-10-30 07:09:00.262 [ome.event.ItemCommandEvent] - Item 'CC_command' received command ON

==> /var/log/openhab2/openhab.log <==

2018-10-30 07:09:00.298 [INFO ] [lipse.smarthome.model.script.coop.py] - Temperature result:108.31

==> /var/log/openhab2/events.log <==

2018-10-30 07:09:00.353 [vent.ItemStateChangedEvent] - CC_command changed from OFF to ON

2018-10-30 07:09:00.479 [vent.ItemStateChangedEvent] - Temperature changed from 28.51 to 108.31

2018-10-30 07:09:01.237 [vent.ItemStateChangedEvent] - CC_command changed from ON to OFF

2018-10-30 07:09:01.259 [vent.ItemStateChangedEvent] - CC_command_out changed from 108.31 to 29.51

The problem is that I’m getting old values or at least I’m not consistent with getting the right one because the item gets updated before the script ends running - as you can see in the log value (Temperature) gets updated with value from previous script run (light level update) and after that command_out changes to reflect the temperature update run.
I thought that the while loop with the //wait until script finishes? comment would make the rule wait for script finish but it’s not - how can I make sure that I update value after script finishes?

Please publish the thing definition
According to the docs you shouldn’t need this second while loop

I already posted it in the first post:

Thing exec:command:coopPythonScript [ command="python /home/openhabian/python/coop.py %2$s", interval=0, autorun=false ]

without the second loop the problem still existed but I will check it again once I get back home

There’s a finite time between sending a command to exec binding and the run state getting updated to ON.
Depends on system performance if you slip through the !=OFF test before that update happens.

Is there some reason not to split rules here, one to trigger the script start and one to trigger on results Item update?

I’m running openhabian on RPI 0W if that makes any difference. I thought of it yesterday but how will I know which value was just updated?

I don’t understand. If you have a rule listening for Item xxx_out updated, that’s the Item that updated.

As far as I understand everything my script prints out will end up in the xxx_out item, and no matter what argument I will pass, right? I’m changing the xxx_Args item (arguments passed to script) to get different values from the same script. If I will listen to xxx_out updated then how can I know which value it was - in other words how will I know that this is a value from -g temp script run and not from -g light run?

I would like not to make a ton of redundant code so that is why I’m trying to use the xxx_Args item.

It’ll still be in the xxx_args Item.state, won’t it?

I think you’ll be better off using the executeCommandLine action

I just tested it and you might be right, where can I find some documentation on it? (google isn’t helpful :slightly_frowning_face:)

I was thinking about your problem today at work.
You are pooling the information from the same python script every 30 seconds
So every 30 seconds you are using a thread (Not for very long) to update two items

Why don’t you make the script send the information to openHAB instead of openHAB asking for it.
You could loop the python script and run it as a service
In the script you can use the REST api to update the items or MQTT

That would be far more efficient

The executeCommandLine works like this:

var myString = executeCommandLine("python /home/openhabian/python/coop.py -g temp", 1000) // 1000ms timeout
Temperature.postUpdate( Float::parseFloat(myString)

Good luck

1 Like

rest api :thinking: I will definitely give it a shot in the next few days, thanks for the suggestion.

I would like also to switch something on and off once a day, lets say it will be a lamp that will turn on for the nigt. But the timing of switching on (evening) and off (morning) will change during a year. I am able to write a script that would calculate the time of these 2 events for each day but if you could point me in the right direction when comes to scheduling these events - what would be the best way to do this (what should I google :wink:)?

Look for the Astro binding

1 Like

Running script as a service seems “meh” but after initial testing the rest api was a good suggestion :grinning: I will probably run script every X seconds with Y timeout, in the script collect all values and push them trough rest api.
Is there a way of detecting that my script timed out other than empty string returned by executeCommandline? (I would have set it up so it returns something after it finishes)

I just started playing around with the Astro binding and I have a question:
If I would like to have possibility of changing my location and offsets do I have any other way than editing the .things file somehow with a script?

Why, are you moving?

No. But you can pre-define more than one location.

astro:sun:home  [ geolocation="52.520,13.404,100", interval=60 ] {
... }
astro:sun:otherhome  [ geolocation="50.99,15.99,200", interval=60 ] {
... }

I don’t think you can. There was just another such discussion yesterday. The astro binding will provide you with 2 things a sun and a moon each with lots of channels. I think each will get the initial location from the general location provided but can be changed. Once. Per thing.
You can change it again and again of course. But why? This a Home Automation platform and as a rule Homes don’t move. Not “normal” ones. This is why the binding is designed that way.

Cave Johnson once said:

Science isn’t about why. It’s about not.

So that is why :stuck_out_tongue: but giving it a second thought you may be right that homes don’t move. What about dynamic offset change? I would really like to have a way of changing this one. Also, am I right about executeCommandline timeout?

No, but you can set up a dynamic timer started by the earliest offset you want.

Ok, why? it makes sense. Start it on boot and forget about it. It runs in the background and updates openHAB through the rest api. Nothing to do in OH.