Need help for http request for a "Grünbeck" water softener

Hello,
I can grap the time of the water softener using curl:

marco@openhab:~$ curl --url http://192.168.222.15/mux_http --data "id=625&show=D_C_4_2~" --silent --output /dev/stdout
<data><code>ok</code><D_C_4_2>03:46</D_C_4_2></data>marco@openhab:~$

I tried the http binding:

String Enthaertung_D_C_4_2_Msg  "Gruenbeck: [%s]"  <water>  {http="<[http://192.168.222.15/mux_http?id=625&show=D_C_4_2~:10000:REGEX((.*))]"}

But the according Item is never updated.
Has anyone an Idea what is wrong here?

Trying to achieve the same thing (I have a Grünbeck SC18). The problem is that the water softener doesn’t return anything for GET requests. You have to do a POST request (which curl does if you use the --data parameter). Unfortunately I haven’t found a way how to do a POST request with the http binding. Seems like POST requests are only supported for “out” bindings but not for “in” bindings.

Or have I missed something?

Hello Michael,
I could not manage to get the http binding working either. I had to do an ugly workaround using scripts.
Here my linux bash script:

#!/bin/bash
#curl --url http://192.168.222.15/mux_http \
#--header "application/x-www-form-urlencoded" \
#--data "id=625&show=D_C_4_2|D_C_5_2|D_A_1_1|D_Y_2_1~" --silent --output /tmp/curlout.txt

xml_field=$1
gruenbeck_ip=dd.dd.dd.dd
curl --url http://$gruenbeck_ip/mux_http --data "id=625&show=$xml_field~" --silent --output /dev/stdout | xmllint --xpath "string(//$xml_field)" --format -

The script is called with the Grünbeck xml field tag, e.g. Durchflusssensor:
/opt/openhab/scripts/gruenbeck.sh D_A_1_1
0.00

This is then used within an openhab rule:

rule "rule-gruenbeck-durchfluss"
when
	Time cron "*/10 * * * * ?"
then
	var String bash_result
	var Float Durchfluss
	loop_counter++

	try {
		bash_result = executeCommandLine("/opt/openhab/scripts/gruenbeck.sh D_A_1_1", 15000)
		Durchfluss = Float::parseFloat(bash_result)
	} catch (NumberFormatException e)
	{
		logWarn("Grünbeck", "parsing error 1, received:" + bash_result)
		return
	}
	postUpdate(Enthaertung_Durchfluss, Durchfluss)
	logInfo("Grünbeck", "Grüni result Durchfluss: " + Enthaertung_Durchfluss.state + " loop: " + loop_counter)
//	sendMail("marco@hoefle.co", "Gruenbeck rule", "Grüni result Durchfluss: " + Enthaertung_Durchfluss.state + " loop: " + loop_counter)
end

The Grünbeck device cannot cope with fast subsequent requests, so an pause of > 10 sec is required.
I am still working on a proper inclusion in openhab. It would be nice to use the http binding though.

Hi,

I had problems too with accessing returned Data from a POST request.
I wanted to investigate this further but had no time.

Anyway you can use a workaround with rules to access the data.


// Filenam for logging purposes
val String filename = "MYRULEFILENAME.rules"

rule "Grab http POST requested Data"
when
    // Your trigger goes here, cron would maybe fit the best
then
    var url = "http://192.168.222.15/mux_http"
    var postUserData = = "id=625&show=D_C_4_2~"

    try{

        // POST Request
        var output = sendHttpPostRequest(url , "application/x-www-form-urlencoded", postUserData)

        // Check if Data arrived and is valid for your usecase
        if(transform("JSONPATH","$.non_field_errors",output) != null){
            throw new Exception(transform("JSONPATH","$.non_field_errors",output))
        }

        // No errors. Update corrsponding Item
        logInfo(filename, "POST update done succesfully.")
        wantedItem.postUpdate(transform("JSONPATH","$.token",output))
        
    }
    catch(Exception e){

        logError(filename, "POST request failed: " + e)

    }

end

The rules is copied from one i have in use currently.
The error check is there because i am requesting an external API for my usecase, so you could drop that maybe.

The important part is:

// POST Request
var output = sendHttpPostRequest(url , "application/x-www-form-urlencoded", postUserData)

With this you should be able to access your data.
Maybe you need to change the application/type parameter.
This depends on your ecosystem.

Maybe this can help you a with simplifying your rule a bit. :slight_smile:

Hello Jerome,
I tired your workaround

rule "Grab http POST requested Data"
when
    Time cron "*/10 * * * * ?"
then
    var url = "http://192.168.222.15/mux_http"
    var postUserData = "id=625&show=D_C_4_2~"

    try{

        // POST Request
        var output = sendHttpPostRequest(url , "application/x-www-form-urlencoded", postUserData)
        logInfo("Grünbeck 1:", output);

        // Check if Data arrived and is valid for your usecase
        if(transform("JSONPATH","$.non_field_errors",output) != null){
            throw new Exception(transform("JSONPATH","$.non_field_errors",output))
        }

        // No errors. Update corrsponding Item
        logInfo("Grünbeck 2:", "POST update done succesfully.")
        Enthaertung_Durchfluss.postUpdate(transform("JSONPATH","$.token",output))
        logInfo("Grünbeck 3:", "Grüni result Durchfluss: " + Enthaertung_Durchfluss.state + " loop: " + loop_counter)    
    }
    catch(Exception e){
        logError("Grünbeck 4:", "POST request failed: " + e)
    }

end

This results in:

09:00:01.003 [ERROR] [.smarthome.model.script.actions.HTTP] - Fatal transport error: java.util.concurrent.TimeoutException
09:00:01.003 [INFO ] [e.smarthome.model.script.Grünbeck 1:] - 
09:00:01.003 [WARN ] [.core.transform.TransformationHelper] - Cannot get service reference for transformation service of type JSONPATH
09:00:01.003 [WARN ] [ore.transform.actions.Transformation] - No transformation service 'JSONPATH' could be found.
09:00:01.003 [INFO ] [e.smarthome.model.script.Grünbeck 2:] - POST update done succesfully.
09:00:01.004 [WARN ] [.core.transform.TransformationHelper] - Cannot get service reference for transformation service of type JSONPATH
09:00:01.004 [WARN ] [ore.transform.actions.Transformation] - No transformation service 'JSONPATH' could be found.
09:00:01.004 [ERROR] [e.smarthome.model.script.Grünbeck 4:] - POST request failed: java.lang.IllegalArgumentException: The argument 'state' must not be null or empty.

Did you install the JSONPATH Transformation through Paper UI and mor important:
Is the JSONPATH Transformation useful for your case?
I can see that you didnt change any values there.

Please read this for explanation:

So

// Check if Data arrived and is valid for your usecase
if(transform("JSONPATH","$.non_field_errors",output) != null){
    throw new Exception(transform("JSONPATH","$.non_field_errors",output))
}

could possibly be removed and

wantedItem.postUpdate(transform("JSONPATH","$.token",output))

could changed to something you want to have.

That depends on the format which will be send from your water softener.
If you can post a raw result here, i can give you a better hint on that.
From your first Post this could be an xml output, but i am not sure.

If its XML you can use the XPATH Transformation for getting the Value directly.
See http://docs.openhab.org/addons/transformations/xpath/readme.html for further information and examples.

So a possible rule for exactly your case could look this:

rule "Grab http POST requested Data"
when
    Time cron "*/10 * * * * ?"
then
    var url = "http://192.168.222.15/mux_http"
    var postUserData = "id=625&show=D_C_4_2~"

    // POST Request
   var output = sendHttpPostRequest(url , "application/x-www-form-urlencoded", postUserData)
   logInfo("Grünbeck 1:", output);

   // No errors. Update corrsponding Item
   logInfo("Grünbeck 2:", "POST update done succesfully.")
   var DurchflussString = transform("XPATH","//D_C_4_2/text()",output)
   Enthaertung_Durchfluss.postUpdate(Float::parseFloat(DurchflussString))
        logInfo("Grünbeck 3:", "Grüni result Durchfluss: " + Enthaertung_Durchfluss.state + " loop: " + loop_counter)    

end

No guarantee for the XPATH, i didnt use it in rules before, but i think this could be the correct way to use it.
For testing XPATh you could use something like:
https://www.freeformatter.com/xpath-tester.html

I hope this can help you solve the Problem. :slight_smile:

Edit:
And of course the Transformation you want to use, has to be installed with Paper UI.


Edit 2 - Since this is the solution post now:
There occurred problems due to the long answer time of that water softener.
The solution for this partly problem was to extend the POST request with a larger timeout (5000 in this case).

var output = sendHttpPostRequest(url, "application/x-www-form-urlencoded", postUserData, 5000)

This is the CURL command:

marco@openhab:~$ curl --url http://192.168.222.15/mux_http --data "id=625&show=D_A_1_1~" --silent --output /dev/stdout
<data><code>ok</code><D_A_1_1>0.00</D_A_1_1></data>marco@openhab:~$ 

Note: The reply from Grünbeck takes ~3 seconds

Ups you were fast with your reply, I’ll try that out soon.
Thanks

As i can see from your curl command you are using different values for the &show parameter.
For this case i would suggest you to use a more generic xpath expression, that you can use in all rules you define for different water softener values.

/data/*[2]/text()

selects the second node in the data element (so D_A_1_1 in your last example) and returns the inner Content (the wanted value) as a string.
This should work properly, as long as the response from that grünbeck device always returns the same xml structure.

Ah and one additional thing:

You could of course do some error checking too, like i did.
It seems that grünbeek validates the request and you could do something like this:

try{

   // Do the http request here

   // Check if Data arrived and is valid for your usecase
   // Only when <code> is not 'ok' we will log an error to openHAB and don't post an update to the item
   if(transform("XPATH","/data/*[1]/text()",output) != "ok"){
       throw new Exception("Water softener doesn't know this data code!")
   }


   // When <code> is 'ok' we will have receive a valid value and can do the postUpdate stuff

}
catch(Exception ex){
   // Log out the error to the openHAB console for better investigation
   logError("Grünbeck 4:", "POST request failed: " + e)
}

Hello Jerome,
I set up the rule using XPATH which would be the most elegant way I think (The XPATH transformation was installed via Paper UI).

I guess the sendHttpPostRequest doesn’t return anything:

10:33:51.004 [ERROR] [.smarthome.model.script.actions.HTTP] - Fatal transport error: java.util.concurrent.TimeoutException
10:33:51.006 [INFO ] [e.smarthome.model.script.Grünbeck 1:] - 
10:33:51.007 [INFO ] [e.smarthome.model.script.Grünbeck 2:] - POST update done succesfully.
10:33:51.008 [ERROR] [ore.transform.actions.Transformation] - Error executing the transformation 'XPATH': the given parameters 'xpath' and 'source' must not be null
10:33:51.009 [ERROR] [ntime.internal.engine.ExecuteRuleJob] - Error during the execution of rule Grab http POST requested Data: null

This might be due to the slow reply times of the Grünbeck water Softner ?

Yes this could be the reason. Tricky problem.
You could force the Rule to wait and see, if the return value is present then.

var output = sendHttpPostRequest(url , "application/x-www-form-urlencoded", postUserData)
Thread::sleep(5000) // The rule will sleep for 5 seconds 

The thread sleep didnt help.

I added two loginfos in the current rule

		logInfo("Grünbeck", "before curl");
		bash_result = executeCommandLine("/opt/openhab/scripts/gruenbeck.sh D_A_1_1", 15000)
		logInfo("Grünbeck", "after curl");

resulting in:

12:08:10.002 [INFO ] [ipse.smarthome.model.script.Grünbeck] - before curl
12:08:11.914 [INFO ] [ipse.smarthome.model.script.Grünbeck] - after curl
12:08:11.917 [INFO ] [ipse.smarthome.model.script.Grünbeck] - Grüni result Durchfluss: 0.0 loop: 4

so it takes nearly two seconds.

adding this

   logInfo("Grünbeck 1:", "start sendHttpPostRequest");
   var output = sendHttpPostRequest(url, "application/x-www-form-urlencoded", postUserData)
   logInfo("Grünbeck 2:", "end sendHttpPostRequest");

results in:
12:18:10.002 [INFO ] [e.smarthome.model.script.Grünbeck 1:] - start sendHttpPostRequest
12:18:11.006 [ERROR] [.smarthome.model.script.actions.HTTP] - Fatal transport error: java.util.concurrent.TimeoutException
12:18:11.008 [INFO ] [e.smarthome.model.script.Grünbeck 2:] - end sendHttpPostRequest

So it looks that sendHttpPostRequest has a timout of ~1000 ms.

I changed this value in
marco@openhab:/etc/openhab2$ cat services/http.cfg
timeout=5000

but it looks that this timeout values is not for sendHttpPostRequest.

Solved, many thanks Jerome.
The sendHttpPostRequest() method is overloaded, a timeout can be passed:

rule "Grab http POST requested Data"
when
    Time cron "*/10 * * * * ?"
then
    var url = "http://192.168.222.15/mux_http"
    var xml_field = "D_A_1_1"
    var postUserData = "id=625&show=" + xml_field + "~"
	loop_counter++

    // POST Request
   logInfo("Grünbeck 1:", "start sendHttpPostRequest");
   var output = sendHttpPostRequest(url, "application/x-www-form-urlencoded", postUserData, 5000)
   logInfo("Grünbeck 2:", "end sendHttpPostRequest");
   logInfo("Grünbeck 3:", output);

   // No errors. Update corrsponding Item
   logInfo("Grünbeck 4:", "POST update done succesfully.")
   var DurchflussString = transform("XPATH","//" + xml_field + "/text()",output)
   Enthaertung_Durchfluss.postUpdate(Float::parseFloat(DurchflussString))
        logInfo("Grünbeck 5:", "Grüni result Durchfluss: " + Enthaertung_Durchfluss.state + " loop: " + loop_counter)    

end

Results:
12:43:20.002 [INFO ] [e.smarthome.model.script.Grünbeck 1:] - start sendHttpPostRequest
12:43:20.939 [INFO ] [smarthome.event.ItemCommandEvent ] - Item ‘Lueftung_Airflow’ received command 166
12:43:21.897 [INFO ] [e.smarthome.model.script.Grünbeck 2:] - end sendHttpPostRequest
12:43:21.897 [INFO ] [e.smarthome.model.script.Grünbeck 3:] - ok<D_A_1_1>0.00</D_A_1_1>
12:43:21.897 [INFO ] [e.smarthome.model.script.Grünbeck 4:] - POST update done succesfully.
12:43:21.909 [INFO ] [e.smarthome.model.script.Grünbeck 5:] - Grüni result Durchfluss: 0.0 loop: 10

Regarding simplifying: The next step would be to have a generic function were the xml_field can be mapped to the different items. I am working on it and post the solution here.

1 Like

Nice to hear that this is solved.
My intention was to move you an a direction where you don’t have to fallback on external scripts, so i am very glad that this worked. :slight_smile:

Please mark your post or my first example as solution, so that others can recognize this directly when looking at this thread. :slight_smile:

1 Like

Hello Jerome,
from time to time the Gruenbeck water softner doesn’t respond. This happens when the native web interface of the device is called.

I tried to catch this using this rule:

val Functions$Function1<String, String> call_gruenbeck = [ xmlField |
	var String url = "http://192.168.222.15/mux_http"
	var String postUserData = "id=625&show=" + xmlField + "~"
	var String xmlStruct
	var String xmlString

	try {
		xmlStruct = sendHttpPostRequest(url, "application/x-www-form-urlencoded", postUserData, 5000)
	}
	catch(Exception ex) {
		sendMail("marco@hoefle.co", "openhab Fehler", "Grünbeck http request failed")
	}

	logInfo("Grünbeck", "Rx XML: " + xmlStruct);

	if (xmlStruct.length < 2) {
		return "-1.0"
	}

	try {
		xmlString = transform("XPATH","//" + xmlField + "/text()", xmlStruct)
	}
	catch(Exception ex) {
		sendMail("marco@hoefle.co", "openhab Fehler", "Grünbeck transform request failed")
		logInfo("Grünbeck", "transform failed!!");
	}

    return xmlString
]



rule "rule-grab_gruenbeck-data"
when
    System started
then
	var Float floatResult
	var Integer intResult
	var String strResult
	var int sleepTime = 10000
	
	Thread::sleep(sleepTime);

	while(true) {
		Enthaertung_Abfragen.postUpdate(loop_counter);

		if(loop_counter%20 == 0) {

			strResult = call_gruenbeck.apply("D_A_3_1")
			logInfo("Grünbeck", "Sting: " + strResult + " loop: " + loop_counter)
			Thread::sleep(sleepTime);

			floatResult = Float::parseFloat(call_gruenbeck.apply("D_Y_2_1"))
			Enthaertung_Wasserverbrauch_gestern.postUpdate(floatResult)
			logInfo("Grünbeck", "Grüni Wasserverbrauch gestern: " + Enthaertung_Wasserverbrauch_gestern.state + " loop: " + loop_counter)
			Thread::sleep(sleepTime);

			floatResult = Float::parseFloat(call_gruenbeck.apply("D_Y_2_2"))
			Enthaertung_Wasserverbrauch_vorgestern.postUpdate(floatResult)
			logInfo("Grünbeck", "Grüni Wasserverbrauch vorgestern: " + Enthaertung_Wasserverbrauch_vorgestern.state + " loop: " + loop_counter)
			Thread::sleep(sleepTime);

			intResult = Integer::parseInt(call_gruenbeck.apply("D_A_2_2"))
			Enthaertung_Wartung_Tage.postUpdate(intResult)
			logInfo("Grünbeck", "Grüni Wartung Tage: " + Enthaertung_Wartung_Tage.state + " loop: " + loop_counter)
			Thread::sleep(sleepTime);

			floatResult = Float::parseFloat(call_gruenbeck.apply("D_A_1_2"))
			Enthaertung_Restkapazitaet.postUpdate(floatResult)
			logInfo("Grünbeck", "Grüni Restkapaziät: " + Enthaertung_Restkapazitaet.state + " loop: " + loop_counter)
			Thread::sleep(sleepTime);

		 
		} else {
			floatResult = Float::parseFloat(call_gruenbeck.apply("D_A_1_1"))
			Enthaertung_Durchfluss.postUpdate(floatResult)
			logInfo("Grünbeck", "Grüni result Durchfluss: " + Enthaertung_Durchfluss.state + " loop: " + loop_counter)
			Thread::sleep(sleepTime);  
		}
		loop_counter++
	}
end

However, the rule completely stops once an error occurs:

10:03:23.191 [INFO ] [ipse.smarthome.model.script.Grünbeck] - Rx XML: <data><code>ok</code><D_A_1_1>0.00</D_A_1_1></data>
10:03:23.206 [INFO ] [ipse.smarthome.model.script.Grünbeck] - Grüni result Durchfluss: 0.0 loop: 1
10:03:33.209 [INFO ] [marthome.event.ItemStateChangedEvent] - Enthaertung_Abfragen changed from 1 to 2
10:03:33.364 [ERROR] [.smarthome.model.script.actions.HTTP] - Fatal transport error: java.util.concurrent.ExecutionException: java.io.EOFException: HttpConnectionOverHTTP@1607603a(l:/192.168.222.118:49161 <-> r:/192.168.222.15:80,closed=false)[HttpChannelOverHTTP@62c7e3cb(exchange=HttpExchange@27a997a8 req=TERMINATED/null@null res=PENDING/null@null)[send=HttpSenderOverHTTP@639d4620(req=QUEUED,snd=COMPLETED,failure=null)[HttpGenerator{s=START}],recv=HttpReceiverOverHTTP@4eb6fcd9(rsp=IDLE,failure=null)[HttpParser{s=CLOSED,0 of 0}]]]
10:03:33.365 [INFO ] [ipse.smarthome.model.script.Grünbeck] - Rx XML: null
10:03:33.366 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Error during the execution of startup rule 'rule-grab_gruenbeck-data': cannot invoke method public int java.lang.String.length() on null
10:03:37.951 [INFO ] [marthome.event.ItemStateChangedEvent] - CurrentDate changed from 2017-11-10T10:02:37.940+0100 to 2017-11-10T10:03:37.940+0100

It seems try catch is not working this way.

Hey Marco,

First thing i would like to mention:
You dont need to build an infinite loop while(true) in the startup rule.
You can do that with a cron based rule, which is a bit better because you are blocking a whole thread with thread::sleep for that time.

I know this is not the problem now, but i wanted to mention it. :smile:

Topic related:
I have to ask some questions, since i don’t own a water softener and i don’t know exactly what you want to happen on specific cases.

Does the try catch work basically and sends those mails to you?
-> If yes we can go on.

Do you want the rule to go on without doing anything, when you get an exception?
If the answer is yes, you should add a return false in those catch blocks.

In your main rule you could then check if the result from your function is different from false and go on with posting updates only in this case.

so it would be something like this:

val response = call_gruenbeck.apply("D_Y_2_1")
if(response != false){
    floatResult = Float::parseFloat(response)
    Enthaertung_Wasserverbrauch_gestern.postUpdate(floatResult)
    logInfo("Grünbeck", "Grüni Wasserverbrauch gestern: " + Enthaertung_Wasserverbrauch_gestern.state + " loop: " + loop_counter)
}

Hello Jerome,
the water softener has a flow sensor and my aim is to detect whenever a water tap is opened as my little son tends to open water taps without closing it :-). Once the rule is active a led in the kitchen is turned on blue. This works as long as the rule is running.

So I need to poll permanently, the fastest http requests to the water softener can be done every 10 seconds. If it is faster then the http request might fail or no xml flle is returned.
From time to time I want the other information like remaining days for service, water used yesterday and the day before yesterday.
I had a cron trigger before but in case I the rule wasn’t finished as it is processing the “other information” failures occurred as the the same rule code might be executed in parallel. Thus I though a while loop might solve this but I guess it is not nice code. On the other hand thread locking mechanism isnt nice either.

Right now the catch block is not executed. Sending mails from other blocks works.

Then you should test the result directly in the tryblock and throw an exception manually, when it doesn#t return a proper value.

try {
    xmlStruct = sendHttpPostRequest(url, "application/x-www-form-urlencoded", postUserData, 5000)
    if(xmlstruct == null){
        throw new Exception
    }    
}
catch(Exception ex) {
	sendMail("marco@hoefle.co", "openhab Fehler", "Grünbeck http request failed")
}

Hopefully the throwing code is right this way. i haven’t thrown exceptions manually in xtend yet.

Hello Jerome,
it seems try catch is not working.
I switched back to cron trigger and use a field counter to avoid concurrent rule execution as under normal circumstances 10 seconds are enough to process one value.
Maybe there are some better solutions but for now it does the trick and hopefully my son stops opening taps anyway in the near future :wink:
Maybe it is helpful to other openhabeners having a Grünbeck water softener:

rule "rule-grab_gruenbeck-data"
when
    Time cron "*/10 * * * * ?"
then
	var Float floatResult
	var Integer intResult
	var String strResult


	if(loop_counter%100 == 0) {
		switch fieldPointer {
			case 0: { 
				strResult = call_gruenbeck.apply("D_A_3_1")
				logInfo("Grünbeck", "Sting: " + strResult + " loop: " + loop_counter)
			}
			case 1: {
				floatResult = Float::parseFloat(call_gruenbeck.apply("D_Y_2_1"))
				Enthaertung_Wasserverbrauch_gestern.postUpdate(floatResult)
				logInfo("Grünbeck", "Grüni Wasserverbrauch gestern: " + Enthaertung_Wasserverbrauch_gestern.state + " loop: " + loop_counter)
			}
			case 2: {
				floatResult = Float::parseFloat(call_gruenbeck.apply("D_Y_2_2"))
				Enthaertung_Wasserverbrauch_vorgestern.postUpdate(floatResult)
				logInfo("Grünbeck", "Grüni Wasserverbrauch vorgestern: " + Enthaertung_Wasserverbrauch_vorgestern.state + " loop: " + loop_counter)
			}
			case 3: {
				intResult = Integer::parseInt(call_gruenbeck.apply("D_A_2_2"))
				Enthaertung_Wartung_Tage.postUpdate(intResult)
				logInfo("Grünbeck", "Grüni Wartung Tage: " + Enthaertung_Wartung_Tage.state + " loop: " + loop_counter)	
			}
			case 4: {
				floatResult = Float::parseFloat(call_gruenbeck.apply("D_A_1_2"))
				Enthaertung_Restkapazitaet.postUpdate(floatResult)
				logInfo("Grünbeck", "Grüni Restkapaziät: " + Enthaertung_Restkapazitaet.state + " loop: " + loop_counter)
			}
		}
		if(fieldPointer == 4) {
			fieldPointer = 0;
		} else {
			fieldPointer++;
		}		 
	} else {
		floatResult = Float::parseFloat(call_gruenbeck.apply("D_A_1_1"))
		Enthaertung_Durchfluss.postUpdate(floatResult)
		logInfo("Grünbeck", "Grüni result Durchfluss: " + Enthaertung_Durchfluss.state + " loop: " + loop_counter)
	}

	Enthaertung_LastUpdate.postUpdate(new DateTimeType())
	loop_counter++
	Enthaertung_Abfragen.postUpdate(loop_counter);	
end

Thank you,
Marco