[SOLVED] JS Transformation script problem

my robotermower succesfully reports it`s driving distance in meters:

Number Landroid_totalDistance "Total Distance [%s m]"  <lawnmower> {mqtt="<[broker:landroid/status/totalDistance:state:default]"}  

I`d like to transform the number from meters in kilometers.
posts in other topics show examples by using JS transformation, so I tried:

Number Landroid_totalDistance "Total Distance [JS(kilometer.js):%s km]"  <lawnmower> {mqtt="<[broker:landroid/status/totalDistance:state:default]"}

and the file kilometer.js in the transform folder:

(function(i) {
    return (i/1000);
}) (input)

unfortunately the script does not work, the item in the sitemap just reports “NaN”. I do not get any failure in the logs.
“Javascript Tranformation” add-on is installed…
any idea whats wrong?

I know I can achieve the same result with a rule like that:

var Number Landroid_km = Landroid_totalDistance.state as DecimalType   
        var Number yy = Landroid_km/1000
      postUpdate(Landroid_totalDistance_km, yy)

but there are some other statistics from that mower that are reported in minutes. I`d like to transform them to hours or days as well. the JS way of doing that seems to be much easier than to write a rule for every single item…

NaN stands for “Not a Number”.

What happens if you apply the transform to the message in the MQTT transform instead of the label? I suspect what is happening is the km is also being passed to the JavaScript transform from the label. It has been a long long time but I believe I’ve seen this issue crop up before and IIRC an issue was even created. Guess it never got fixed.

That helps for the KM -> M conversion.

I’ve this JS that converts minutes to days:hours:mins that you can extend as necessary.

(function(i) {
    if(isNaN(i)) return "NAN";
    var mins = i%60
    var totalhours = Math.floor(i/60)
    var hours = totalhours%24
    var days = Math.floor(totalhours/24)
    var pad = "00";
    return days+":"+(pad+hours).slice(-pad.length)+":"+(pad+mins).slice(-pad.length)+":00";

Put the transformation in the binding:

Number Landroid_totalDistance "Total Distance [%.1f km]"  <lawnmower> { mqtt="<[broker:landroid/status/totalDistance:state:JS(kilometer.js)]" }

Your transformmation is failing because the parameter passed to it i is a String…

(function(i) {
    return (parseInt(i)/1000);
}) (input)

You could also take advantage of the new Units of Measurement in openHAB:


Number:Length Landroid_totalDistance "[%.1f m]"  <lawnmower> { mqtt="<[broker:landroid/status/totalDistance:state:default]" }

Now your item is in metres

In the sitemap:

Text item=Landroid_totalDistance label="Total Distance [%.1f km]"

It will be converted into km automagicaly

For the minutes to Days and Hours I use this:

Javascript transform function to change the number
of minutes of CPU time from the System Info Binding
into a more readable format
eg: 2365 into '1 day 15 hours 25 minutes

The item in the items file is defined as follow:
Number LocalComputer_Cpu_SystemUptime "[JS(CPUTime.js):%s]"
and linked via PaperUI to the System uptime channel
of the System Info Thing

(function(i) {
    if (i == 'NULL') { return i; }
    if (i == '-') { return 'Undefined'; }
    var val = parseInt(i); // The value sent by OH is a string so we parse into an integer
    var days = 0; // Initialise variables
    var hours = 0;
    var minutes = 0;
    if (val >= 1440) { // 1440 minutes in a days
        days = Math.floor(val / 1440); // Number of days
        val = val - (days * 1440); // Remove days from val
    if (val >= 60) { // 60 minutes in an hour
       hours = Math.floor(val /60); // Number of hours
        val = val - (hours * 60); // Remove hours from val
    minutes = Math.floor(val); // Number of minutes

    var stringDays = ''; // Initialse string variables
    var stringHours = '';
    var stringMinutes = '';
    if (days === 1) {
        stringDays = '1 day '; // Only 1 day so no 's'
    } else if (days > 1) {
        stringDays = days + ' days '; // More than 1 day so 's'
    } // If days = 0 then stringDays remains ''

    if (hours === 1) {
        stringHours = '1 hour '; // Only 1 hour so no 's'
    } else if (hours > 1) {
        stringHours = hours + ' hours '; // More than 1 hour so 's'
    } // If hours = 0 then stringHours remains ''

    if (minutes === 1) {
        stringMinutes = '1 minute'; // Only 1 minute so no 's'
    } else if (minutes > 1) {
        stringMinutes = minutes + ' minutes'; // More than 1 minute so 's'
    } // If minutes = 0 then stringMinutes remains ''

    var returnString =  stringDays + stringHours + stringMinutes
    return returnString.trim(); // Removes the extraneous space at the end

1 Like

thanks for the fast response, you were both right!
indeed, the “km” from the label

"Total Distance [JS(kilometer.js):%s km]"

was forwareded to the js and therefore failed. it works without “km” but then I was missing the unit in the sitemap.
the magic “Number:Length” does the trick, it can also convert to cm, dm, miles etc, greate! it even shows the correct decimal point “,” instead of “.”

both minutes convertion .js work fine, but wouldn`t be the “Number:Time” magic also worth to be implemented?

Number Landroid_totalTime "Total Time [JS(minutestohours.js):%s]"  <lawnmower> {mqtt="<[broker: landroid/status/totalTime:state:default]"}

many thanks!

Glad you worked it out. Can you mark the solution, please

It would be great but the formatting would be a nightmare :smile: