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

That sounds really weird.
I will try to test some try catch blocks in my environment.

Hello Community,
I am new to the openHAB system and also try to integrate my Grünbeck water softener. Can someone give me a step by step guide? I tried to understand the steps, but unfortunately without success. Sorry for my English, better in German, but I try it in English. I did not understand what the items, rules and scripts should look like. Do I have to leave a script at all or just pass the rules and items?

Hello,
can you ping the Gruenbeck water softener from your device were openhab2 is running?

Take this rule, modify the url, copy it into the rules directory of your openhab2 installation (e.g. /etc/openhab2/rules/gruenbeck.rules ):


import org.eclipse.xtext.xbase.lib.Functions

var int loop_counter = 0
var int fieldPointer = 0


val Functions$Function1<String, String> call_gruenbeck = [ xmlField |
	var String url = "http://192.168.1.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) {
		return "-1.0"
	}

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


	try {
		xmlString = transform("XPATH","//" + xmlField + "/text()", xmlStruct)
	}
	catch(Exception ex) {
		logInfo("Grünbeck", "transform failed!!");
		return "-1.0"
	}

    return xmlString
]



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




rule "rule-gruenbeck-wasser-marsch"
when
	Item Enthaertung_Durchfluss changed
then

	if (Enthaertung_Durchfluss.state > 0.0) {
		postUpdate(Enthaertung_Wasser_Marsch, ON)
	} else {
		postUpdate(Enthaertung_Wasser_Marsch, OFF)
	}
end


Use this items file and copy it into the items folder (e.g. /etc/openhab2/items/gruenbeck.items ):

Group gEnthaertung
Group gEnthaertung_Chart

String Enthaertung_Zeit_Str
String Enthaertung_Datum_Str

Number Enthaertung_Wasserverbrauch_gestern
Number Enthaertung_Wasserverbrauch_vorgestern
Number Enthaertung_Wartung_Tage
Number Enthaertung_Restkapazitaet
Number Enthaertung_Abfragen
DateTime Enthaertung_LastUpdate

Number Enthaertung_Chart_Period     "Chart Period"
Number Enthaertung_Durchfluss "Wasserverbrauch" (gEnthaertung, gEnthaertung_Chart)

Switch Enthaertung_Wasser_Marsch

Finally integrate the items into your sitemap:

		Text item=Enthaertung_Durchfluss label="Enthärtung [%.1f m\u00b3/h]" icon="faucet" {
			Frame label="Status" {
				Text item=Enthaertung_Wartung_Tage label="Tage bis zur nächsten Wartung: [%d]" icon="clock"
				Text item=Enthaertung_Durchfluss label="Durchfluss [%.1f m\u00b3/h]" icon="faucet"
				Text item=Enthaertung_Wasserverbrauch_gestern label="Wasserverbrauch gestern [%d L]" icon="water"
				Text item=Enthaertung_Wasserverbrauch_vorgestern label="Wasserverbrauch vorgestern [%d L]"icon="water"
				Text item=Enthaertung_Restkapazitaet label="Restkapazität [%.2f m\u00b3]" icon="water"
				Text item=Enthaertung_Abfragen label="Debug: Loops [%d]" icon="settings"
				Text item=Enthaertung_LastUpdate label="Last Update [%1$ta %1$tR]" icon="clock"
			}

You should see this in the log:

07:58:11.926 [INFO ] [lipse.smarthome.model.script.Grünbeck] - Rx XML: <data><code>ok</code><D_A_1_1>0.00</D_A_1_1></data>
07:58:11.930 [INFO ] [lipse.smarthome.model.script.Grünbeck] - Grüni result Durchfluss: 0.0 loop: 62
07:58:11.932 [INFO ] [smarthome.event.ItemStateChangedEvent] - Enthaertung_LastUpdate changed from 2018-01-02T07:58:01.933+0100 to 2018-01-02T07:58:11.931+0100
07:58:11.933 [INFO ] [smarthome.event.ItemStateChangedEvent] - Enthaertung_Abfragen changed from 62 to 63

BR
Marco

1 Like

Hello Marco, thank you for your help! It works partly some values ​​are displayed but the following “next maintenance”, “water consumption the day before yesterday”, “remaining capacity” are unfortunately not displayed. I will attach the error messages from the log.

2018-01-04 21:27:30.873 [ERROR] [.smarthome.model.script.actions.HTTP] - Fatal transport error: java.util.concurrent.ExecutionException: java.io.EOFException: HttpConnectionOverHTTP@e223ae(l:/172.168.100.12:36288 <-> r:/172.168.100.152:80,closed=false)[HttpChannelOverHTTP@679693(exchange=HttpExchange@19edd5b req=TERMINATED/null@null res=PENDING/null@null)[send=HttpSenderOverHTTP@44b7ca(req=QUEUED,snd=COMPLETED,failure=null)[HttpGenerator@1f608ff{s=START}],recv=HttpReceiverOverHTTP@1a9cf1c(rsp=IDLE,failure=null)[HttpParser{s=CLOSED,0 of 0}]]]
2018-01-04 21:27:30.882 [ERROR] [ore.transform.actions.Transformation] - Error executing the transformation 'XPATH': the given parameters 'xpath' and 'source' must not be null
2018-01-04 21:27:30.886 [ERROR] [ntime.internal.engine.ExecuteRuleJob] - Error during the execution of rule 'rule-grab_gruenbeck-data': null

Thank you,
Christian

Hello Marco, it works.

Thank you
Christian

Hello Christian,
good to hear.
The errors you see I get from time to time as well.
This is due to the Gruenbeck response times, sometimes the Grünbeck doesn’t respond or responds with an empty xml string.
The error handling in the rules doesn’t work the expected way.
BR
Marco

Hi Marco (@marco_hoefle), this is very helpful.

What Transformation package is necessary to install with PaperUI? XPATH or JSON Path?

Did you modified something which could be shared? Because I got lots of errors and only sometimes values back from my Grünbeck SC18.

Many Thanks, Tino

Hello Tino,
here is my actual rules file:

import org.eclipse.xtext.xbase.lib.Functions

var int loop_counter = 0
var int fieldPointer = 0


val Functions$Function1<String, String> call_gruenbeck = [ xmlField |
	var String url = "http://YOUR_GB_IP/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")
		return "-1.0"
	}

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


	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 "-1.0"
	}

    return xmlString
]



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




rule "rule-gruenbeck-wasser-marsch"
when
	Item Enthaertung_Durchfluss changed
then

	if (Enthaertung_Durchfluss.state > 0.0) {
		postUpdate(Enthaertung_Wasser_Marsch, ON)
	} else {
		postUpdate(Enthaertung_Wasser_Marsch, OFF)
	}
end

the items:

Group gEnthaertung
Group gEnthaertung_Chart

String Enthaertung_Zeit_Str
String Enthaertung_Datum_Str

Number Enthaertung_Wasserverbrauch_gestern
Number Enthaertung_Wasserverbrauch_vorgestern
Number Enthaertung_Wartung_Tage
Number Enthaertung_Restkapazitaet
Number Enthaertung_Abfragen
DateTime Enthaertung_LastUpdate

Number Enthaertung_Chart_Period     "Chart Period"
Number Enthaertung_Durchfluss "Wasserverbrauch" (gEnthaertung, gEnthaertung_Chart)

Switch Enthaertung_Wasser_Marsch

the sitemap part:

		Text item=Enthaertung_Durchfluss label="Enthärtung [%.1f m\u00b3/h]" icon="faucet" {
			Frame label="Status" {
				Text item=Enthaertung_Wartung_Tage label="Tage bis zur nächsten Wartung: [%d]" icon="time"
				Text item=Enthaertung_Durchfluss label="Durchfluss [%.1f m\u00b3/h]" icon="faucet"
				Text item=Enthaertung_Wasserverbrauch_gestern label="Wasserverbrauch gestern [%d L]" icon="water"
				Text item=Enthaertung_Wasserverbrauch_vorgestern label="Wasserverbrauch vorgestern [%d L]"icon="water"
				Text item=Enthaertung_Restkapazitaet label="Restkapazität [%.2f m\u00b3]" icon="water"
				Text item=Enthaertung_Abfragen label="Debug: Loops [%d]" icon="settings"
				Text item=Enthaertung_LastUpdate label="Last Update [%1$ta %1$tR]" icon="time"
			}
			Frame {
				Switch item=Enthaertung_Chart_Period label="Chart Period" icon="chart" mappings=[0="Hour", 1="Day", 2="Week"]
				Chart item=gEnthaertung_Chart period=h refresh=600 visibility=[Enthaertung_Chart_Period==0, Enthaertung_Chart_Period=="NULL"]
				Chart item=gEnthaertung_Chart period=D refresh=3600 visibility=[Enthaertung_Chart_Period==1]
				Chart item=gEnthaertung_Chart period=W refresh=3600 visibility=[Enthaertung_Chart_Period==2]
			}
		}

Fyi: I’ve created a binding for reading out the values. It is in a early state, but generally you’re already able to read out some values (not all yet). I’d appreciate anyone who’d like to test it and give feedback. Thanks!
It’s available from Eclipse marketplace

3 Likes

Hi Matthias,

thanks for the binding, it works grear so far.

I noticed that some values (e.g. D_A_1_1, D_A_1_2, D_A_2_2) are missing, but I am not sure whether this is intentional.

I tried to alter the things-types.xml file accordingly, but just replacing it in the JAR-file lead to a “handler not found error” (I did not use an IDE…) This may be a different topic, but what did I do wrong?

I could send a DIFF file, if it was easy for you to update it.

Thanks,
Veit

Hi Matthias,

thanks for your work. Can you also provide a jar-file to install the addon? Because I’m not using eclipse. Or is there another way to install it?

Thanks,
Mario

Hi Mario,

you can use the download link on the eclipse page for downloading the jar-file (e.g. just copy the link into the adress line of your browser). Then copy the jar file to the addons folder.

BR, Veit

1 Like

Ah, now I got it, thanks!
It’s the first time I use this :wink:

Hi!
I installed the binding and it works great. For the moment I just use it to save my water consumption and display it in Grafana.
I have one more question: Is there a way to use the ntp-binding from openhab to set the time on the gruenbeck? I still have problems with the time. It looks like it is not possible to set on the webif. When I change it and press “OK”, nothing happens. It’s still the old value.

Mario

Thank you for this binding!! can you add this?
D_A_1_1
D_Y_10_1
D_Y_13
D_A_3_1
D_A_1_3
D_A_1_2
D_K_3

i am using your binding right now and it seems to work like a charm. thank you very much for your effort!