Using a javascript with JSON Transform through MQTT

Not sure if this topic makes sense. I didn’t know how to call it.

I’m wondering if this is possible, maybe I don’t have the right combination of how to do it, but I have tried to tinker and not seemed to be able to get it right.

What i’m doing is taking a time in seconds from my 3D Printer that is publishing to my MQTT server then using a javascript (PrintTime.js) that takes the the seconds and converts it to Days, Hours, Min, Sec.

This is how my items is set up, and it works. Only problem is that it does not auto refresh/update on my sitemap, and I have to refresh the page every time I want to see the updated time.

Below is my item config for this.

`

Number		Enders3_EstimatedTime		"Estimated Time [JS(PrintTime.js):%s]"	<clock> (gEnders3)		{mqtt="<[mosquitto:octoprint/progress/printing:state:JSONPATH($.printer_data.job.estimatedPrintTime)]"}

`

Is there a way I can take that script and automatically run it through the JSONPATH Transform before it gets updated to my item itself, ( Hoping that this will make it automatically update on the sitemap).

I’ve tried something like this but it says I have errors with the transform.

 Number		Enders3_EstimatedTime		"Estimated Time: [%s]"	<clock> (gEnders3)		{mqtt="<[mosquitto:octoprint/progress/printing:state:JS(PrintTime.js):JSONPATH($.printer_data.job.estimatedPrintTime)]"}

Not sure if this is possible or not, or if I have to go through a rule to get what I am looking to get. Any help is appreciated.

Thank You!

I’m fairly sure you can apply only one transform at a time.

You could perhaps cobble up a joint javascript that did it’s own JSON thing and then the rest.

1 Like

I’m not too good with java, kinda pieced together stuff myself to get these to work :rofl: Not sure how i would even start to do that :see_no_evil:

Post your PrintTime.js
I’ll show you, quite easy

(function(i) {
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;
var seconds = 0;

if (val >= 86400) { // 86400 seconds in a days
    days = Math.floor(val / 86400); // Number of days
    val = val - (days * 86400); // Remove days from val
}
if (val >= 3600) { // 3600 seconds in an hour
   hours = Math.floor(val /3600); // Number of hours
    val = val - (hours * 3600); // Remove hours from val
}

  if (val >= 60) { // 60 seconds in an minute
   minutes = Math.floor(val /60); // Number of hours
    val = val - (minutes * 60); // Remove hours from val
}

seconds = Math.floor(val); // Number of seconds



var stringDays = ''; // Initialse string variables
var stringHours = '';
var stringMinutes = '';

var stringSeconds = ‘’;

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 ''

if (seconds === 1) {
stringSeconds = ‘1 Second’; // Only 1 second so no ‘s’
} else if (seconds > 1) {
stringSeconds = seconds + ’ Seconds’; // More than 1 second so ‘s’
} // If seconds = 0 then stringMinutes remains ‘’

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

})(input)

So I did get it to work by just creating a simple rule and it updates on the sitemap correctly how I would like it to by doing the following… (for further searchers like myself :+1:)

rule "Update Print Time"
when
		Item Enders3_PrintTime  changed
then
	Enders3_PrintTime.postUpdate(transform("JS","PrintTime.js",(Enders3_PrintTime.state as StringType)))
 
end
1 Like

Ok so, parse the JSON a the top:



    (function(jsonString) {
    //JSON BIT
    var data = JSON.parse(jsonString)
    var val = parseInt(data.printer_data.job.estimatedPrintTime);parse into an integer
    //YOUR RULE
    var days = 0; // Initialise variables
    var hours = 0;
    var minutes = 0;
    var seconds = 0;

    if (val >= 86400) { // 86400 seconds in a days
        days = Math.floor(val / 86400); // Number of days
        val = val - (days * 86400); // Remove days from val
    }
    if (val >= 3600) { // 3600 seconds in an hour
       hours = Math.floor(val /3600); // Number of hours
        val = val - (hours * 3600); // Remove hours from val
    }

      if (val >= 60) { // 60 seconds in an minute
       minutes = Math.floor(val /60); // Number of hours
        val = val - (minutes * 60); // Remove hours from val
    }

    seconds = Math.floor(val); // Number of seconds



    var stringDays = ''; // Initialse string variables
    var stringHours = '';
    var stringMinutes = '';

    var stringSeconds = ‘’;

    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 ''

    if (seconds === 1) {
    stringSeconds = ‘1 Second’; // Only 1 second so no ‘s’
    } else if (seconds > 1) {
    stringSeconds = seconds + ’ Seconds’; // More than 1 second so ‘s’
    } // If seconds = 0 then stringMinutes remains ‘’

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

    })(input)

Your new item:

String		Enders3_EstimatedTime		"Estimated Time [%s]"	<clock> (gEnders3)		{mqtt="<[mosquitto:octoprint/progress/printing:state:JS(PrintTime.js)]"}

another question…

So if I have multiple items like so

Number		Enders3_EstimatedTime		"Estimated Time [JS(PrintTime.js):%s]"	<clock> (gEnders3)		{mqtt="<[mosquitto:octoprint/progress/printing:state:JSONPATH($.printer_data.job.estimatedPrintTime)]"}
String		Enders3_PrintTime			"Current Print Time: [JS(PrintTime.js):%s]"	<clock> (gEnders3)		{mqtt="<[mosquitto:octoprint/progress/printing:state:JSONPATH($.printer_data.progress.printTime)]"}
String		Enders3_PrintTimeLeft		"Print Time Left: [JS(PrintTime.js):%s]"	<clock> (gEnders3)		{mqtt="<[mosquitto:octoprint/progress/printing:state:JSONPATH($.printer_data.progress.printTimeLeft)]"}

I have to create multiple PrintTime.js to make this work then?

or is there a way to take the JSON path and input it as the variable?

Yep

Not without a proxy item

OK,

Thanks for your help and lesson! :smiley:

Careful with that - it’s an endless loop waiting to bite you.

1 Like

Delete that rule, you don’t need it anymore with the new transformation

Actually David wrote it so you can chain transforms. But I have no experience with it so can’t tell you how to do it.

I couldn’t find an example but I know he talked about it being possible. Maybe it’s something that is planned? Yep, found it, it’s in work and not yet available. Mqtt 2.5

1 Like