[SOLVED] Reading value from shell script, Tinkerforge Outdoor Weather Station

Maybe we should ask @theo if he already has plans (and time!) to implement new bricklets.

You need to escape the characters in the Thing

Thing exec:command:get_outdoorweather_temp [command="/home/user/tinkerforge/tinkerforge --host 192.168.178.137 --port 4223 call outdoor-weather-bricklet Es8 get-sensor-data 24 --execute \"echo 'scale=2; {temperature} / 10' | bc | xargs printf '%.1f\n\'"", interval=0, autorun=true]

Thank you!

with this thing (changed the \ one step to the right)

Thing exec:command:get_outdoorweather_temp [command="/home/rot/tinkerforge/tinkerforge --host 192.168.178.137 --port 4223 call outdoor-weather-bricklet Es8 get-sensor-data 24 --execute \"echo 'scale=2; {temperature} / 10' | bc | xargs printf '%.1f\n'\"", interval=0, autorun=true]

this rule should update the item

Number TF_Outdoor_Temperature "Aussen Temp.  [%.1f °C]"
rule "Your Execution"
  when
     Item YourTrigger changed
  then
      TF_Outdoor_Temperature.postUpdate((Integer::parseInt(get_outdoorweather_temp.state.toString) as Number ))

the result in the log file is

[ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Your Execution': The name 'get_outdoorweather_temp' cannot be resolved to an item or type; line 26, column 32, length 2

Hmmmm…

Yes. Also i would like to learn, how to develeop this binding. Perhaps Theo can give us a hint.

In this post, Theo is also asked for his help: Tinkerunity Tinkerforge Openhab Development

You can’t use a Thing’s name in the scripts
Add the channel to your item like a binding:

{channel=“exec:command:apc:output”}

Number TF_Outdoor_Temperature "Aussen Temp.  [%.1f °C]" { channel="exec:command:get_outdoorweather_temp:output" }

But you will need to change the interval in you thing definition depending on how often you want the value to be pulled

As @vzorglub already said you can not link a thing as trigger for the rule.
Have a look at the detailed example to get a better understanding on how things work.

changed this to:

Thing exec:command:get_outdoorweather_temp [command="/home/user/tinkerforge/tinkerforge --host 192.168.178.137 --port 4223 call outdoor-weather-bricklet Es8 get-sensor-data 24 --execute \"echo 'scale=2; {temperature} / 10' | bc | xargs printf '%.1f\n'\"", interval=30, timeout=15, autorun=false]

the thing ist successfully loaded but i can not see a execution within 30 seconds, nor a error or the temperature shown in the user inferface.

I tought, a rule is needed to update this thing. But ok, there is this interval feature.

I read this thread. They are “sending” values/arguments to a shell script. I am searching for the “opposite” way around: “reading” a value from an script.

This was meant for a better understanding of things channels items etc, as it is explained there in detail.

You may follow up with this where basically is done what you do.

There is a " missing after the =.

As your command directly returns only the value you can link the output channel directly to the item and it should work, no need for a rule.

Ooops sorry

Thank you!
Found this missing ".

Read your suggested post.

Ok, this string item should receive the value directly from the “channel” of the “thing”.

Thing:

Thing exec:command:get_outdoorweather_temp [command="/home/user/tinkerforge/tinkerforge --host 192.168.178.137 --port 4223 call outdoor-weather-bricklet Es8 get-sensor-data 24 --execute \"echo 'scale=2; {temperature} / 10' | bc | xargs printf '%.1f\n'\"", interval=0, autorun=true]

String item:

String TF_Outdoor_Temperature { channel="exec:command:get_outdoorweather_temp:output" }

And from there on, a rule is needed to convert the string into a number?

Your thread:

Is there a direct way to debug this string? Perhaps my userinterface can’t show the string. Or, perhaps, the script isn’t executed at all.

Now I will refer to my first post :wink:

Make a switch to trigger a rule and trigger the command line, then post the returned value from the execution to the log. Watch the log and press the button. See what is returned back.

Did you try to execute the command as user openhab in the command line? ( This is shown in the examples).

What I could imagine is that echo or xargs does not work with the exec command as the user openhab does not execute commands with a bash. So this has to be enabled or the conversion, stripping of the result has to be done in a rule.

I would suggest you try to do the switch to trigger a rule and then try to execute the script without echo then with echo and see what is in the log.

I never thought about user priviliges.

You were testing this with:

sudo -u openhab /opt/vc/bin/vcgencmd measure_temp

and this works in my shell with user “openhab”

 sudo -u openhab /home/user/tinkerforge/tinkerforge --host 192.168.178.137 --port 4223 call outdoor-weather-bricklet Es8 get-sensor-data 24 --execute "echo 'scale=2; {temperature} / 10' | bc | xargs printf '%.1f\n'"

The result is: “30,2”. No problem.

That’s good, but still this is executed in a bash.

Other thing could be the ,. Maybe you have German as language for the pi and English for openhab. And this makes trouble.

followed your suggestion:

Number TF_Outdoor_Temperature "Aussen Temp.  [%.1f °C]" <temperature> (gTemperaturen)
String TF_Outdoor_Temperature_out "[%s]" { channel="exec:command:get_outdoorweather_temp:output" }
Thing exec:command:get_outdoorweather_temp [command="/home/user/tinkerforge/tinkerforge --host 192.168.178.137 --port 4223 call outdoor-weather-bricklet Es8 get-sensor-data 24 --execute \"echo 'scale=2; {temperature} / 10' | bc | xargs printf '%.1f\n'\"", interval=30, autorun=true]

and the rule

rule "Convert String to Item Type and reading temparature value"
  when
    Item YourTrigger changed
    then
    
    // post the new value to the Number Item
    postUpdate( TF_Outdoor_Temperature.toString , TF_Outdoor_Temperature_out.state.toString )

    logInfo("Rule was triggered", " state "+ TF_Outdoor_Temperature_out.state) 
 end

these are the results.

 [INFO ] [home.model.script.Rule was triggered] -  state NULL
 [ERROR] [ui.internal.items.ItemUIRegistryImpl] - Cannot retrieve item 'get_outdoorweather_temp_out' for widget org.eclipse.smarthome.model.sitemap.Text
 [ERROR] [ui.internal.items.ItemUIRegistryImpl] - Cannot retrieve item 'get_outdoorweather_temp_out' for widget org.eclipse.smarthome.model.sitemap.Text
rule "Convert String to Item Type and reading temparature value"
when
    Item TF_Outdoor_Temperature_out changed
then
    logInfo("Rule was triggered", "state " + TF_Outdoor_Temperature_out.state.toString) 
    // post the new value to the Number Item
    postUpdate("TF_Outdoor_Temperature", TF_Outdoor_Temperature_out.state.toString)
end

Hello Vincent,

thank you for your patient correction of my rule. I thought, the item “TF_Outdoor_Temperature_out” can’t change itself, but it is bound to the thing, which updates every 30s. OK.

But, sadly, OH ist not happy:

 [ERROR] [ui.internal.items.ItemUIRegistryImpl] - Cannot retrieve item 'get_outdoorweather_temp_out' for widget org.eclipse.smarthome.model.sitemap.Text
[ERROR] [ui.internal.items.ItemUIRegistryImpl] - Cannot retrieve item 'get_outdoorweather_temp_out' for widget org.eclipse.smarthome.model.sitemap.Text

I think, i should try the following steps:

a) use a simple “dummy” script, to check the openHAB syntax and mechanism
b) trying to use the regex transformation. But, before digging into this transformation, i would like to know, if the data from shell script is transfered correctly to openHAB.

Have a good day! :slight_smile:

this regex way:

the output from the script is:

temperature=251
humidity=43
last-change=20

on https://regex101.com/ with “temperature=(.) humidity=(.)” the result is

Group 1. 12-15 440
Group 2. 25-27 43

So, IF the data from the script find its way into openHAB; then there should be a way to transform it to the corresponding number items “Humidity” and “Temperature”.

What i meant was something like this.

Switch ExecuteComand 
Switch RunScript { channel="exec:command:get_outdoorweather_temp:run" }
String TF_Outdoor_Temperature_out "[%s]" { channel="exec:command:get_outdoorweather_temp:output" }

Attention i removed the --execute echo ... part to first see if the script gets executed and the expected values are shown.


Thing exec:command:get_outdoorweather_temp [command="/home/user/tinkerforge/tinkerforge --host 192.168.178.137 --port 4223 call outdoor-weather-bricklet Es8 get-sensor-data 24", interval=0, autorun=false]
rule "Execute Script and get back return value"
  when
    Item ExecuteComand changed
    then
    
    RunScript.sendCommand(ON)

     // Wait for the command to complete.
     while(RunScript.state != OFF){
       Thread::sleep(100)
     }

    logInfo("Script executed", TF_Outdoor_Temperature_out.state.toString) 
 end

Hello Josar,

used your rule with a longer sleep time

rule "Execute Script and get back return value"
  when
    Item ExecuteComand changed
    then
    
    RunScript.sendCommand(ON)

     // Wait for the command to complete.
     while(RunScript.state != OFF){
       Thread::sleep(1000)
     } 
    logInfo("Script executed", TF_Outdoor_Temperature_out.state.toString) 
 end

and one time, i see this on the log:

 [el.core.internal.ModelRepositoryImpl] - Refreshing model 'tf_outdoorweather_exe.rules'
[ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Execute Script and get back return value': An error occurred during the script execution: null

I altered the rule a bit

rule "Execute Script and get back return value"
  when
    Item ExecuteComand changed
    then
    
    RunScript.sendCommand(ON)

     // Wait for the command to complete.
     /* while(RunScript.state != OFF){
       Thread::sleep(1000)
     } */
       Thread::sleep(5000)

    logInfo("Script executed", TF_Outdoor_Temperature_out.state.toString) 
 end

this time, i’m seeing this

[INFO ] [arthome.model.script.Script executed] - NULL

Then i started a new try, this time using the demo phython script from tinkerforge:

user@openhab:~/tinkerforge$ sudo -u openhab python /home/user/tinkerforge/example_callback.py
Press key to exit
21
21
21

“21” is the humidity, it occours after 25s after the call, and will be repeated, till you press a key.

New Thing:

Thing exec:command:weatherstation_humidity "Luftfeuchtigkeit" [command="python /home/user/tinkerforge/example_callback.py", transform="REGEX((.*?))", interval=60, timeout=50, autorun=true]

and new items:

Number Weatherstation_Humidity    "Luftfeuchtigkeit [%.1f %%]" <humidity> 
String humidity_out    { channel="exec:command:weatherstation_humidity:output" }

and a rule (also tried the commented section)

rule "Weatherstation Humidity"
  when
     //Item humidity_out received update
     Item ExecuteCommandHumidity changed
  then
      logInfo("Humidity Phython Script executed", humidity_out.state.toString) 
      
     // Weatherstation_Humidity.postUpdate(
     //      ( Float::parseFloat(humidity_out.state.toString) as Number )
      //)
end

(i looked at this example: OpenHAB Raspberry Weatherstation )

BUT, no result in Openhab:

 [INFO ] [ipt.Humidity Phython Script executed] - NULL

Wooaah, that is really difficult! :slight_smile:

The Tinkerforge python script:

user@openhab:~/tinkerforge$ cat example_callback.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

HOST = "192.168.178.137"
PORT = 4223
UID = "Es8" # Change XYZ to the UID of your Outdoor Weather Bricklet

from tinkerforge.ip_connection import IPConnection
from tinkerforge.bricklet_outdoor_weather import BrickletOutdoorWeather

# Callback function for station data callback
def cb_station_data(identifier, temperature, humidity, wind_speed, gust_speed, rain,
                    wind_direction, battery_low):
    print("Identifier (Station): " + str(identifier))
    print("Temperature (Station): " + str(temperature/10.0) + " °C")
    print("Humidity (Station): " + str(humidity) + " %RH")
    print("Wind Speed (Station): " + str(wind_speed/10.0) + " m/s")
    print("Gust Speed (Station): " + str(gust_speed/10.0) + " m/s")
    print("Rain (Station): " + str(rain/10.0) + " mm")
    print("Wind Direction (Station): " + str(wind_direction))
    print("Battery Low (Station): " + str(battery_low))
    print("")

# Callback function for sensor data callback
def cb_sensor_data(identifier, temperature, humidity):
#    print("Identifier (Sensor): " + str(identifier))
#    print("Temperature (Sensor): " + str(temperature/10.0) + " °C")
    print(str(humidity))    # Here i disabled the other outputs: station identifier and temperature
#    print("")

if __name__ == "__main__":
    ipcon = IPConnection() # Create IP connection
    ow = BrickletOutdoorWeather(UID, ipcon) # Create device object

    ipcon.connect(HOST, PORT) # Connect to brickd
    # Don't use device before ipcon is connected

    # Enable station data callbacks
    ow.set_station_callback_configuration(True)

    # Enable sensor data callbacks
    ow.set_sensor_callback_configuration(True)

    # Register station data callback to function cb_station_data
    ow.register_callback(ow.CALLBACK_STATION_DATA, cb_station_data)

    # Register sensor data callback to function cb_sensor_data
    ow.register_callback(ow.CALLBACK_SENSOR_DATA, cb_sensor_data)

    raw_input("Press key to exit\n") # Use input() in Python 3
    ipcon.disconnect()

I wrote “Theo” a message, but it seems, that he is not active in this forum anymore.