Item Transformations using .JS and trying to pass parameter

Hi,
After upgrading to 4.02 i thought i have some cleanup, remove unnecessary items and calculations done in NodeRed, what i need is to pass a parameter to a transformation, this is a cut down item file

Number:Temperature nSolTemp3_t "Temp. Tank Solfanger T3" <Temperature> (gSolStatus2) ["Measurement", "Temperature"]  {channel="mqtt:topic:stest:temperatur3"[profile="transform:JS", toItemScript="scaleOffs.js?offs=9"]}

and this is the script:

(function(d, f) {
   var DIVIDE_BY = 10;
   var MyData = parseFloat(d) + parseFloat(f);
   var result parseFloat(MyData) / parseFloat(DIVIDE_BY);
   return result.toString();
})(input, offs)

Cutting down the scrip and hardcopding the parameter, and removing the ?offs=9 it works fine, but i would like my script to have this parameter as its different on each item. And while im at it, and I know that there is so much knowledge out there, pls show mee how to pas multiple parameters…

Thanks Ole

Just to clarify, the js script was not the correct one in last post:

(function(d, f) {
   var DIVIDE_BY = 10;
   var MyData = parseFloat(d) + parseFloat(f);
   return parseFloat(MyData) / parseFloat(DIVIDE_BY);
})(input, offs)

/Ole

JS

(function(input) {
   var DIVIDE_BY = 10;
   var MyData = (parseFloat(input) + parseFloat(offs)) / DIVIDE_BY;
   return MyData.toString();
})(input)

JRuby:

(input.to_f + offs.to_f) / 10

Thanks for the reply,
still doesn’t work though, do i have the right syntax in the items file ?

Number:Temperature nSolTemp3_t "Temp. Tank Solfanger T3" <Temperature> (gSolStatus2) ["Measurement", "Temperature"]  {channel="mqtt:topic:stest:temperatur3"[profile="transform:JS", toItemScript="scaleOffs.js?offs=9"]}

And shouldnt there be some reverense to the offs parameter in the function definition ?

/Ole

Your item syntax seems correct. I have tested it and also tested the JS that I posted above. offs is simply a variable that’s been injected, with that name, into the scripting engine so you can access it. I’m not familiar with JS but my test script doesn’t reference it in the function definition like what you think it should.

Did you see anything in your openhab.log?

Try this JS:

(function(input) {
   return Quantity(input).add(offs).divide(10).toString();
})(input)

It should work either way. input is injected the same as offs is in this case.

It’s on my list of things to explore but I don’t think the (function... stuff is required either. I’m sure it’s JS best practice but we are not coding stuff that runs in a webpage or has to live along side a bunch of other libraries. I think the following would work.

return Quantity(input).add(Quantity(offs, '°C')).divide('10 °C');

Quantity definitely does have a toString() so that call should be redundant. But add and divide requires either a String or a Quantity, not just a plain number. It doesn’t know what units the plain number should have. Another alternative is to pass the 9 with units.

Or strip the units and add them back.

var value = (Quantity(input).float + parseFloat(offs)) / 10;
return value + ' °C'

I’m not sure what happens if you pass what is already a float to parseFloat. At a minimum it’s redundant. Maybe that’s the error?

Unfortunately a simple return like that doesn’t work in JS, but it does in JRuby.

BTW when doing multiplication / division of a Quantity type, don’t use a unit in the operand, because that unit gets multiplied / divided too.

So 1 °C * 5 °C = 5 °C^2 (the resulting unit is celsius squared) and 1 °C / 1 °C = 1 (the unit is gone).

Doh! That’s right. But I wonder if it works the same as for UI script conditions without the return.

In that case it works the same as Rules DSL lambdas. What ever the last line of the script evaluates to is what gets returned.

That depends on the unit. The library can be smart. I don’t think °C^2 is a thing so it should either just fail outright or stick with °C. The library is smart enough to recognize that V*W = A (which was a surprise to me) .

But if it’s not smart in this case, the units need to be stripped off and the added back after the calculation. I show how to do that above.

I’m trying to put a few minutes together to test some things out.

Hi,
Just to get some context, i have this script :

(function(data) {
   var div = 10;
   return parseFloat(data) / div;
})(input)

Together with this item(s) that works just fine:

Number:Temperature nSolTemp3 "Temp. Tank Solfanger" <Temperature> (gSolStatus2) ["Measurement", "Temperature"]  {channel="mqtt:topic:Solfanger:temperatur3"[profile="transform:JS", toItemScript="scale2.js"]}

And in the original script if i do this without the parameter the script works just fine:

(function(d) {
   var DIVIDE_BY = 10;
   var MyData = parseFloat(d) + parseFloat(3);
   return parseFloat(MyData) / parseFloat(DIVIDE_BY);
   
})(input)

With or without the .toString part.

/Ole

Again, MyData is already a float at this point. I don’t know if parseFloat works if you try to parse something that’s already a float. And even if it can, it’s pointless to parse it. The same goes for DIVIDE_BY. They are already numbers. There’s nothing to parse.

Notice how the transformation you report works just fine doesn’t parseFloat div.

Ok this was strange, just restarted Openhab (for some unrelated reason) and now this actually works (Jims solution):

Number:Temperature nSolTemp3_t "Temp. Tank Solfanger T3" <Temperature> (gSolStatus2) ["Measurement", "Temperature"]  {channel="mqtt:topic:stest:temperatur3"[profile="transform:JS", toItemScript="scaleOffset.js?offs=1"]}

(function(input) {
   var DIVIDE_BY = 10;
   var MyData = (parseFloat(input) + parseFloat(offs)) / DIVIDE_BY;
   return MyData.toString();
})(input)

So I guess its solved, but now how do I pass two parameters, thats the next challenge…

/Ole

Same as you would to a web page. Add another ?varname=value

Thanks Ill give it a go right away.

Ok, some strange behavior, I experience I need to remove, and the add the item each time to get the changes to stick.
Then i tried this, but with no luck.

Number:Temperature nSolTemp3_t "Temp. Tank Solfanger T3" <Temperature> (gSolStatus2) ["Measurement", "Temperature"]  {channel="mqtt:topic:stest:temperatur3"[profile="transform:JS", toItemScript="scaleOffset2.js?offs=3?ratio=10"]}

with this script (basicly the same but i move the DIVIDE_BY out as a separate parameter

(function(input) {
   var MyData = (parseFloat(input) + parseFloat(offs)) / parseFloat(ratio);
   return MyData.toString();
})(input)

/Ole

Doh, brain fart. Use & for subsequent arguments.

scaleOffset2.js?offs=3&ratio=10

Note that it uses the same syntax as web pages.

Thanks, again,
Your help is highly valued…

Final solution for the one looking for it later:

Number:Temperature nSolTemp3_t "Temp. Tank Solfanger T3" <Temperature> (gSolStatus2) ["Measurement", "Temperature"]  {channel="mqtt:topic:stest:temperatur3"[profile="transform:JS", toItemScript="scaleOffset2.js?offs=3&ratio=10"]}


scaleOffset2.js


(function(input) {
   var MyData = (parseFloat(input) + parseFloat(offs)) / parseFloat(ratio);
   return MyData.toString();
})(input)

Thanks to Rikoshak and JimT for your help.

/Ole

Is it possible to not return a value at all? I would like to filter outliers.

Yes it’s possible. You would return null (not the UnDefType NULL) to do this. This behaviour is documented.

Thanks. Would that trigger the item changed rule trigger ?