[OH3, http-binding, regex] How to change values of heat pump with http2-binding

Tags: #<Tag:0x00007fc910b64168>

Dear all,

I am using http2 binding in OH3 for logging the data of my heat pump with REGEX. Actually this works perfectly and the setup is much more easier than in OH2. Thanks for the new binding! :slight_smile:

What I now want to do: beside the pure logging of the values, I want to change some of them by a rule in certain cases. My heat pump provides an local URL where all relevant values are shown and some of them can be changed directly in the UI.

For example please find the code snippet of the heat pump UI for the value “Fusspunkt”:

    <script language="javascript" type="text/javascript">
      valSettings['val16'] = new Array();
      valSettings['val16']['type'] = 'float';       valSettings['val16']['min'] = '0';
      valSettings['val16']['max'] = '20';
      
            
      jsvalues['16'] = new Array();
      jsvalues['16']['id']='val16';
      jsvalues['16']['val']='0,5'; // the 0,5 should be changed via OH to e.g. 0,0
    </script>

Upto now I only read the value by a REGEX (==> capturing the string)
REGEX used as state transformation:

REGEX:.*jsvalues.'16'..'val'.='(.{1,4})';.*

and replace the decimal comma to a decimal point (==>Number) in a rule.

To be honest I have no idea how to write now… I actually used putRequests in OH2 already and I know that there can be setup command transforamtions also within the Channel. But how does the command transformation look like for this case?

And the second question is how to “send” the putRequest then? Do I need to simply change the String Item with something like the following?

sendCommand(LWZFusspunktHK1_IN, "0,0")

Hopefully there is someone who can point me in the right direction. If there are more data necessary, please let me know! Thanks!

If you want to send commands back through an http:url thing channel you’ll need to set up the ‘Command URL Extension’ and ‘Command Transform’ fields on the channel. Command URL Extension adds extra stuff to the end of the url thing base URL. And command transform is for performing a transform on the item’s value before injecting it into the command url extension. You also can set the method (GET vs POST vs PUT) for commands in the advanced properties of the http:url thing itself.

An example, you can disable a pi-hole for 30 seconds by sending a GET to <pihole ip>/admin/api.php?disable=30. The base url of the pi-hole http:url thing is <pihole ip>/admin/api.php. To support the command you have to configure the channel and go into the advanced properties and add the part that needs to be added to the base URL to handle the command: ?disable=%2$s so that he binding will create the proper url when a linked item receives a command. With a number item linked to this channel, when if you were to sendCommand(PiHoleDisable, "30") the 30 string would get stuck into the URL and then sent on to the pi-hole.

Hi Justin,

thanks for your reply, this is highly appreciated!
I got your description. But to be honest I still do not know how to handle the transformation in my case. There is no specific URL to send the command (like in your example with an extension ?disable=30) in my case. The specific URL contains several values for several measureands / setup values and I want to change some of them.

Maybe some more details will help: This is a part of the code of my thing, in this case for just reading the value “ISTWERT HK1” every 60seconds and save it in the database:

UID: http:url:HTTPLWZ
label: HTTP LWZ
thingTypeUID: http:url
configuration:
  authMode: BASIC
  ignoreSSLErrors: false
  baseURL: http://192.168.2.XX
  refresh: 60
  commandMethod: GET
  timeout: 7500
  bufferSize: 2048
channels:
  - id: Istwert_HK1
    channelTypeUID: http:string
    label: Istwert HK1
    description: ""
    configuration:
      mode: READONLY
      stateExtension: /?s=1,0
      stateTransformation: REGEX:.*ISTWERT HK1</td>\n. *<td class=.value.>(.{1,5}) °C.*

I am capturing the value (in fact it’s a string due to decimal comma, but this doesn’t matter now) with REGEX.
What I do not know - or actually I have absolutely no idea - is how the command transformation needs to look like for changing the value? I guess I do still need a REGEX to “find” the relevant string (acc. to the starting post it’s 0,5 for “Fusspunkt”) but how to replace this with e.g. 0,0 then?

Regards,
Sascha

It is going to depend on how the changing of a value from the device’s UI is implemented. How do you change it from that UI? There may be some clues in the html on what you need to do.

Within the UI the relevant measureand can be changed by 1) typing in the value (blue marked) or increase / decrease it with the red marked arrows and 2) press the save button:

The specific code of this website for “Fusspunkt” looks like this:

<script language="javascript" type="text/javascript">
      valSettings['val16'] = new Array();
      valSettings['val16']['type'] = 'float';       valSettings['val16']['min'] = '0';
      valSettings['val16']['max'] = '20';
      
            
      jsvalues['16'] = new Array();
      jsvalues['16']['id']='val16';
      jsvalues['16']['val']='0,5'; // the 0,5 should be changed via OH to e.g. 0,0
    </script>

Add the end you can see the current value ‘0,5’ which should be changed by a rule to e.g. ‘0,0’.

When you press that save button, your browser is going to send off a request of some sort containing the values to be updated (or possible all of the values in the form). When OH sends a command to update that value, it’ll need to send the command to the same endpoint that the website does. The code you have there appears to be the code for display and validation of the field on the page and not for submitting new values to the device.

I would expect that this page is set up with an HTML form and that save button is the submit for the form. The form should have an action endpoint, be it a page or a call to another javascript function. HTML Forms

If you look around in the page’s code some more you should be able to find a form tag with some more information. Using the browser’s development tools and the inspect function on the save button can help locate the form in the code. Also the network log of the browser dev tools can be helpful as you can watch for what the browser sends off when you click the save button.

Got it. It’s now getting difficult for me since I do not really know what I am looking for.
However, at least I found the following in the code:

edit: 1) code of the displaying website by clicking view page source
Right before the code for displaying the values which I’ve posted above, there’s a form mentioned:

 <form id="werte" action="#" onsubmit="saveValues(this);return false;"><div id="content">

edit: 2) code of the displaying website by clicking view page source
The code of the save-button looks like this:

 <div class="button left"  onclick="document.forms['werte'].onsubmit();"><div class="bg_r">&nbsp;</div><a>Speichern</a></div>  </div>

I tried to find out what happens when the save button is clicked with the dev tool of chrome like you recommended. As far as I understand the relvant code is in “scripts.js” - but actually there are running a lot of javascripts… Please find the code within scripts.js which has something to do with “save”(German: speichern):

edit: 3) code within scripts.js which was found by Network log of Chrome developer tool. Script.js is running when clicking the save button. Indeed, there are running approx. 20 other .js’ also, but the others seem to have nothing to do with saving the values.

//edit: whole function now shown
[...]
function saveChange(form,id,otto)
{
	//alert(form[0].value); // for debugging
	
	
	if (saveChangeRunning)
		return;

	saveChangeRunning = true;
		
	var params = "?msg=";
	var page = "./confirm.php";
	var error = false;
	var dataString = '';

	//Bei Fehlern können wir nicht abspeichern
	for (bid in errorBrain) {
		//Noch ein Fehler gespeichert?
		if (errorBrain[bid]==1)
		{
			if (!error) params += "Ungültige Angaben können nicht gespeichert werden, bitte angezeigte Fehler korrigieren!";
			error = true;
		}
	}
	//Fortsetzen?
	if (!error)
	{
		var success = false;
		var warning = false;
		if (id=='')
		{

			//Array speichern
			if(otto)
				var data = $("#welcome_form").serializeArray();
			else
				var data = $("#werte").serializeArray();
			dataString = JSON.stringify(data);
				
		}
		else
		{
			//Einzelnen Wert speichern
			var val = getValue(id,'');
			if (val)
			{
				var output = eval("document.getElementById(id+'info')");
				if (output)
				{
					output.value = val;
					dataString = '[{"name":"'+id+'","value":"'+val+'"}]';
				}
			}
			hide(id);
		}
		if (dataString!='')
		{
			if(otto)
				var seite = "./ersteinst.php";
			else
				var seite = "./save.php";

			 //console.log(dataString);				// for debugging

			$.post(seite, {data: dataString}, function(answer)
			{
			//alert(answer); // for debugging
			//console.log(answer);
				
				var results = JSON.parse(answer);
				
				//Erfolg?
				if (results['success']==true)
					success = true;
				else if (results['warning']==true)
				{
					success = true;
					warning = true;
				}
				else
				{
					//Fehler übergeben?
					if (results['errors'])
					{
						var errors = results['errors'];
						for (webID in errors)
						{
							var errormsg = errors[webID];
							//Fehler bei Feld webID!
							var $cal = $("#calval"+webID);
							$cal.addClass("fehler");
	    					errorBrain['val'+webID] = 1;
	    					//Fehlermeldung ausgeben => muss später der Infotext wiederhergestellt werden?
							$cal.children("div.green").children("p").html(errormsg);
						}
					}
				}
				if (results['message']!=undefined && results['message']!="")
					params += escape(results['message']);
				if (otto && results['url']!="" && results['url']!=undefined)
					params += "&amp;"+"url="+results['url'];    // OTTO
	
				//Was passiert nun?
				if (!success)
					page = "./error.php";
				else
					if (warning)
						page = "./warning.php";
				params += "&amp;KeepThis=true&amp;TB_iframe=true&amp;height=140&amp;width=420";
				//Meldung
				
				tb_show('',page+params);
				if (!otto)
					form.target=$('#TB_iframeContent').attr('name');
			  	
			  	//Alle Änderungen sind gesichert
				if (success)
					valueChanged = false;
					
				saveChangeRunning = false;
			}, 'text');
		} else
		{
			error = true;
			params += "Es wurde kein zu sichernder Wert gefunden!";
		}
	}
	if (error)
	{
		var errorShown = false;
	  	//Dashboard? Meldung anzeigen!
	 	var $containerDiv = $("#"+id+"edit");
		if ($containerDiv)
		{
		 	var msgDiv = $containerDiv.children("div.dashboardmsg");
			if (msgDiv)
			{
				msgDiv.css("display","block");
				errorShown = true;
				setTimeout(function(){msgDiv.css("display","none")},6000);
			}
		}
		//Nicht doppelt anzeigen
		if (errorShown)
		{
			page = "./error.php";
			params += "&amp;KeepThis=true&amp;TB_iframe=true&amp;height=140&amp;width=420";
			//Meldung
			tb_show('',page+params);
		  	form.target=$('#TB_iframeContent').attr('name');
		}
		saveChangeRunning = false;
	}
	else
	{
	  	//Dashboard? Meldung ausblenden!
	 	var $containerDiv = $("#"+id+"edit");
		if ($containerDiv)
		{
		 	var msgDiv = $containerDiv.children("div.dashboardmsg");
			if (msgDiv)
				msgDiv.css("display","none");
		}
		closeAllBoxes();
	}
}

edit: 4) code within script.js ==> function saveValues:

[...]
function saveValues(f) 
{
	saveChange(f,'');
	return false;
}
[...]

edit: If I understand correctly the saveValues function is just firing the saveChange function from above?

The mentioned save.php is the msgbox which confirms that the values were saved. The code is just the following (nothing more):
edit: code added

{success: true, message: "Die Einstellungen wurden erfolgreich gespeichert."}
message: "Die Einstellungen wurden erfolgreich gespeichert."
success: true

As fas as I understand the values themselves seems to be stored in werte (German word for values) as this appears several times in the relevant code. But I could not find anything further…

Hopefully these information are somehow helpful?

And once again, many thanks that you are guiding my step by step and hint by hint!

Is the code that you pasted in there from a “saveValues” function? The saveValues function gets called when you click the button.

You may want to look a little further down and see where seite is being used. I would guess that the values in dataString are being sent in a request to save.php in some form when you click the button.

I’ve edited the post above:

  • more detailed description where the single codes are comming from
  • added whole code of function saveChange
  • added code of function saveValues
  • added code of save.php

Is this helpful?

@justinwilczek: could you find some time to check the code whether you have any idea?

Ok. So, I think that the script sends a POST with werte as a JSON payload to save.php. So naturally, you’ll need to do the same.

The first thing would be to put save.php into the commandExtension field, so that when you send a command to an item connected to that channel it will send the request there.

Next step is to figure out how to transform the command sent to the item into a JSON payload to send. This part I’m not sure how to accomplish. My guess is that you put the JSON in some form into the commandTransformation field but I can’t be sure. Looking at the http binding source, for a POST the command should get added to the request content but I’m not sure how the command transform relates to the actual content that will get put in.

If you look deeper in chrome’s dev tools you should be able drill down and see the actual content of the request that the script sent to save.php. The trick is just trying to get the http binding to replicate something similar.