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

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.

Did you install the exec Binding?

Please delete all related things and items, rules (maybe all) and use (maybe only) the example exactly as it is shown. Restart openab. Press the Switch and watch the log. (If there are problems with other Things beeing executed repeatedly but not working properly this might lead to problems as they can block the execution of the rule as they occupy the threads. So maybe just set up only this example.)

I did not set up a sitemap but i thought this would be obvious.

sitemap Test label="Test Script"
{
     Frame label="Execute Script"
    {
        Switch item=ExecuteComand
    }
}

increasing the sleept in the while has no effect, besides longer waiting till the script is executed.
Removing the while is a bad idea as the execution is not finished then and the value in TF_Outdoor_Temperature_out.state will be null or from the previous execution.

Yees! (or Nooooo!) I was so sure, i installed both extensions (Regex and Exec) via karaf. But now, i looked at PaperUI - and they weren’t installed!

Now:
246 │ Active │ 80 │ 2.3.0.201805271653 │ Exec Binding

And now, voila:

[INFO ] [arthome.model.script.Script executed] - temperature=269
humidity=21
last-change=43

Now, i will try to convert these string to numbers.

I would think the best solution is a repeatedly executed thing and just parse the 2 (3) values from the output to items temp and hum in a rule. This is the most efficient way and avoids more calls to the bricklet as necessary.

Something like this:

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=60, autorun=false]
String TF_Outdoor_Temperature_out "[%s]" { channel="exec:command:get_outdoorweather_temp:output" }

This rule is not testet and might contain errors, the regex is adapted to be able to skip the newlines in the returned string.

rule "Convert Weather info"
  when
    Item TF_Outdoor_Temperature_out changed 
 then
   
    val data = triggeringItem.state.toString

    val temp = transform("REGEX","s/temperature=(\\d+)\\s.+\\s.+/$1/g", data)
    val hum = transform("REGEX","s/.+\\shumidity=(\\d+)\\s.+/$1/g", data)

    // post the new value to the Number Item
    postUpdate( ... )
    postUpdate( ... )
 end

Hava a look here for an explanation of the regex

one thing, which fetches the string form the tinkerforge station,
and one rule to parse the string into the different numbers?

Can i use Regex within a rule?

And - a big “THANK YOU!” for your help! :slight_smile:

See adapted post above.

Works! (But it is too hot here … 270 Grad Celsius instead of 27 Grad Celsius. :slight_smile:

(new “string” type here:)

String TF_Outdoor_Temperature_string "[%s]" { channel="exec:command:get_outdoorweather_temp:output" }
Number TF_Outdoor_Temperature_number "Outdoor Temperature [%.1f °C]"
Number TF_Outdoor_Humidity_number "Humidity [%.1f %%]"

and your rule

rule "Convert Tinkerforge Weather Station info"
  when
    Item TF_Outdoor_Temperature_string changed 
 then
   
    val data = triggeringItem.state.toString

    val temp = transform("REGEX","s/temperature=(.*?)\\s.+\\s.+/$1/g", data)
    val hum = transform("REGEX","s/.+\\shumidity=(.*?)\\s.+/$1/g", data)

    // post the new value to the Number Item
    postUpdate(TF_Outdoor_Temperature_number,temp)
    postUpdate(TF_Outdoor_Humidity_number,hum)
end

and the output ist (in the OH iOS App):

Outdoor Temperature: 270,0 °C
Humidity: 21,0 %

:slight_smile:

The script runs every second. Is it triggered with the rule by itself?

The intervall in the thing defintion is “interval=60”.

The thing executes every 60 seconds as configured with the interval, then the output is updated. When the output item changes it triggers the rule. You can devide the temperature in the rule before posting to the number item.

Easily said … :slight_smile:

import org.java.math.*

and 

temp = temp / 10

But openHAB don’t know the division “/”

And this script really runs every second. Perhaps i will make the rule cron based, starting every hour.

Just change the thing interval to the time you like. One hour would be 3600 seconds.

Thing exec:command:get_outdoorweather_temp [command="...", interval=3600, autorun=false]

And for the other question, the result is a string, this must be converted to a float and then it can be devided.

val temp = Float::parseFloat(transform("REGEX","s/temperature=(\\d+)\\s.+\\s.+/$1/g", data)) / 10

Hello Josar and Vincent,

thank you very much for your help and patience!

Temperature and Humidity is now displayed in a chart which is showing the outdoor temperature.

In the logs, the script/rule is executed every second - don’t know why. As long it is not slowing down openHAB, i can live with that.

Best regards!

How is the interval of the thing specified?

as you wrote, in seconds: “interval=60”.

What is the trick, to transform this output:

temperature=279
humidity=27
wind-speed=0
gust-speed=0
rain=0
wind-direction=wind-direction-error
battery-low=false
last-change=5

I copied your rules, adapted them, but the transformation does not work:

    val data2 = triggeringItem.state.toString

    val temp2 = Float::parseFloat(transform("REGEX","s/temperature=(.*?)\\s.+\\s.+/$1/g", data2)) / 10
    val hum2 = transform("REGEX","s/.+\\shumidity=(.*?)\\s.+/$1/g", data2)

Output:

[ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Convert Outdoor Tinkerforge Weather Station info': For input string: "279
gust-speed=0
rain=0
wind-direction=wind-direction-error
battery-low=false
last-change=44"

Strange: at the beginning, the word “temperature” is missing.

First, i mixed up the variable names in the rules. I corrected that. Perhaps i should restart OH.

And I said this is why the rule executes every minute. :joy:

You need a \\s.+ for each newline in the returned string. As you can see also the 2 lines following the temperature are missing.

No! Despite the argument in the thing (intervall=60), i can see one entry _every _ second in the log. (Sometimes every second second.) :slight_smile: I think i didn’t mixed up seconds with minutes. :slight_smile:

Is the rule executed every second? Do you have multiple trigger?
Is the skript executed every second? Do you have multiple items running the script?

What is the output in the log?

Restarting OH is allways a good idea after changes, imho.

In the log, the output from command “logInfo” is shown every second. Therfore, i think the rule is executed every second.

I do not habe any other triggers than your both rules.

The transformation (line detection!) works (for me like magic :slight_smile: )

val temp2 = Float::parseFloat(transform("REGEX","s/temperature=(.*?)\\s.+\\s.+\\s.+\\s.+\\s.+\\s.+\\s.+/$1/g", data2)) / 10  // You need a \\s.+ for each newline in the returned string
    val hum2 = transform("REGEX","s/.+\\shumidity=(.*?)\\s.+\\s.+\\s.+\\s.+\\s.+\\s.+/$1/g", data2) // here too!

Thank you!