3D Printer Status and Commands from/to Octoprint via HTTP REST API

Yes the printer is working, i just made copy paste with this result:


JSONPath Transformation is installed and i have added the items with “Text item” to the sitemap

It’s difficult to say what is wrong. I expect one of the following:

  • The .rules - file is not importet correctly. Check in the karaf if the file is loaded and there are no errors during import
  • You run an old OH version and need to add the java imports that do the calculations

I am running the actual stable release (i think it’s 2.1). The calculated values were updated :grinning: but with a very slow rate, i would say every 15minutes :thinking:.
I reduced the update time in the *.items file to 6000ms, but the rules were triggered less often.

Well that is great - so the rules are working!

I am running OH 2.2 beta from a few days ago on a Raspberry Pi 2 and I get updated values every 60 sec.

For everyone who wants to reboot/shutdown their Octoprint Raspi, you’re welcome:

Selection item=OctoprintSystemCommand mappings=[1="herunterfahren",2="Drucker neustarten",3="Service neustarten",4="Abgesicherten Modus starten"]
rule "POST System Kommando"
when
	Item OctoprintSystemCommand received update
then
var String PrinterCmd = ""
    switch (OctoprintSystemCommand.state.toString){
    case "1":
    {PrinterCmd = "shutdown"}
    case "2":
    {PrinterCmd = "reboot"}
    case "3":
    {PrinterCmd = "restart"}
    case "4":
    {PrinterCmd = "restart_safe"}
    }
    logInfo(filename, "Folgende Operation wurde auf den Ender 3 ausführt: " + PrinterCmd )
    var url = 'http://octopi/api/system/commands/core/' + PrinterCmd + '?apikey=XXXXXXXXXXXX'
    //var contenttype = "application/json"

    var output = sendHttpPostRequest(url)
    logInfo(filename, output);
end

everything is working but i get warnings at my log when i shutdown the printer .

2018-11-30 16:20:53.819 [WARN ] [ab.binding.http.internal.HttpBinding] - Transformation 'JSONPATH($.temperature.bed.actual)' threw an exception. [response=Printer is not operational]

org.openhab.core.transform.TransformationException: Invalid path '$.temperature.bed.actual' in 'Printer is not operational'

	at org.openhab.core.transform.TransformationHelper$TransformationServiceDelegate.transform(TransformationHelper.java:67) [216:org.openhab.core.compat1x:2.3.0]

	at org.openhab.binding.http.internal.HttpBinding.execute(HttpBinding.java:194) [226:org.openhab.binding.http:1.12.0]

	at org.openhab.core.binding.AbstractActiveBinding$BindingActiveService.execute(AbstractActiveBinding.java:144) [216:org.openhab.core.compat1x:2.3.0]

	at org.openhab.core.service.AbstractActiveService$RefreshThread.run(AbstractActiveService.java:166) [216:org.openhab.core.compat1x:2.3.0]

2018-11-30 16:20:53.987 [WARN ] [ab.binding.http.internal.HttpBinding] - Transformation 'JSONPATH($.temperature.tool0.target)' threw an exception. [response=Printer is not operational]

org.openhab.core.transform.TransformationException: Invalid path '$.temperature.tool0.target' in 'Printer is not operational'

	at org.openhab.core.transform.TransformationHelper$TransformationServiceDelegate.transform(TransformationHelper.java:67) [216:org.openhab.core.compat1x:2.3.0]

	at org.openhab.binding.http.internal.HttpBinding.execute(HttpBinding.java:194) [226:org.openhab.binding.http:1.12.0]

	at org.openhab.core.binding.AbstractActiveBinding$BindingActiveService.execute(AbstractActiveBinding.java:144) [216:org.openhab.core.compat1x:2.3.0]

	at org.openhab.core.service.AbstractActiveService$RefreshThread.run(AbstractActiveService.java:166) [216:org.openhab.core.compat1x:2.3.0]

2018-11-30 16:20:54.178 [WARN ] [ab.binding.http.internal.HttpBinding] - Transformation 'JSONPATH($.temperature.bed.target)' threw an exception. [response=Printer is not operational]

org.openhab.core.transform.TransformationException: Invalid path '$.temperature.bed.target' in 'Printer is not operational'

	at org.openhab.core.transform.TransformationHelper$TransformationServiceDelegate.transform(TransformationHelper.java:67) [216:org.openhab.core.compat1x:2.3.0]

	at org.openhab.binding.http.internal.HttpBinding.execute(HttpBinding.java:194) [226:org.openhab.binding.http:1.12.0]

	at org.openhab.core.binding.AbstractActiveBinding$BindingActiveService.execute(AbstractActiveBinding.java:144) [216:org.openhab.core.compat1x:2.3.0]

	at org.openhab.core.service.AbstractActiveService$RefreshThread.run(AbstractActiveService.java:166) [216:org.openhab.core.compat1x:2.3.0]

2018-11-30 16:20:54.202 [WARN ] [ab.binding.http.internal.HttpBinding] - Transformation 'JSONPATH($.temperature.tool0.actual)' threw an exception. [response=Printer is not operational]

org.openhab.core.transform.TransformationException: Invalid path '$.temperature.tool0.actual' in 'Printer is not operational'

	at org.openhab.core.transform.TransformationHelper$TransformationServiceDelegate.transform(TransformationHelper.java:67) [216:org.openhab.core.compat1x:2.3.0]

	at org.openhab.binding.http.internal.HttpBinding.execute(HttpBinding.java:194) [226:org.openhab.binding.http:1.12.0]

	at org.openhab.core.binding.AbstractActiveBinding$BindingActiveService.execute(AbstractActiveBinding.java:144) [216:org.openhab.core.compat1x:2.3.0]

	at org.openhab.core.service.AbstractActiveService$RefreshThread.run(AbstractActiveService.java:166) [216:org.openhab.core.compat1x:2.3.0]

2018-11-30 16:20:54.253 [WARN ] [ab.binding.http.internal.HttpBinding] - Transformation 'JSONPATH($.state.text)' threw an exception. [response=Printer is not operational]

org.openhab.core.transform.TransformationException: Invalid path '$.state.text' in 'Printer is not operational'

	at org.openhab.core.transform.TransformationHelper$TransformationServiceDelegate.transform(TransformationHelper.java:67) [216:org.openhab.core.compat1x:2.3.0]

	at org.openhab.binding.http.internal.HttpBinding.execute(HttpBinding.java:194) [226:org.openhab.binding.http:1.12.0]

	at org.openhab.core.binding.AbstractActiveBinding$BindingActiveService.execute(AbstractActiveBinding.java:144) [216:org.openhab.core.compat1x:2.3.0]

	at org.openhab.core.service.AbstractActiveService$RefreshThread.run(AbstractActiveService.java:166) [216:org.openhab.core.compat1x:2.3.0]

Me too, this is normal for unavailable http-binding stuff. Nothing much you can do except changing the logging level.

There is now an mqtt plugin for octoprint, so I will write up a guide how to use it that way soon!

I changed the rule a little bit, so that I dont get Errors anymore:

rule "Time Printed String"
when
	Item OctoprintJobPrintTime changed
then
    val seconds = (OctoprintJobPrintTime.state as DecimalType).intValue
    val int totalMinutes = seconds/60
    val int remainderSecs = seconds%60
    val int totalHours = totalMinutes/60
    val int remainderMins = totalMinutes%60
    val formattedTime = String::format("%02d", totalHours) + ":" + String::format("%02d", remainderMins) + ":" + String::format("%02d", remainderSecs)
    OctoprintJobPrintTimeString.postUpdate(formattedTime)
end

rule "Time Left String"
when
	Item OctoprintJobPrintTimeLeft changed
then
    val seconds = (OctoprintJobPrintTimeLeft.state as DecimalType).intValue
    val int totalMinutes = seconds/60
    val int remainderSecs = seconds%60
    val int totalHours = totalMinutes/60
    val int remainderMins = totalMinutes%60
    val formattedTime = String::format("%02d", totalHours) + ":" + String::format("%02d", remainderMins) + ":" + String::format("%02d", remainderSecs)
    OctoprintJobPrintTimeLeftString.postUpdate(formattedTime)

    val DateTime OctoprintETA = now.plusSeconds(seconds)
    //logInfo("Testing" ,"Octoprint ETA: " + OctoprintETA.toString)
    OctoprintJobPrintETAString.postUpdate(OctoprintETA.toString)
    OctoprintJobPrintETADateTime.postUpdate(new DateTimeType(OctoprintETA.toString))

end

rule "POST Printer Command"
when
	Item OctoprintPrinterCommand received update
then
    var url = "http://xxx.xxx.xxx.xxx/api/job?apikey=YYYYYYYYYYYYYYYYYYYYYY"
    var contenttype = "application/json"
    var POSTrequest = '{"command":"' +  OctoprintPrinterCommand.state + '"}'

    var output = sendHttpPostRequest(url, contenttype, POSTrequest)
    
    logInfo("Test Octoprint:", output);
end

rule "POST System Command"
when
	Item OctoprintSystemCommand received update
then
    var url = 'http://xxx.xxx.xxx.xxx/api/system/commands/core/' + OctoprintSystemCommand.state + '?apikey=YYYYYYYYYYYYYYYYYYYYYY'
    //var contenttype = "application/json"

    var output = sendHttpPostRequest(url)
    
    logInfo("Test Octoprint:", output);
end


rule "Octoprint Status"
when
	Time cron "0 0/2 * 1/1 * ? *"
then

var String JOctoprintPrinterState = sendHttpGetRequest("http://xxx.xxx.xxx.xxx/api/connection?apikey=YYYYYYYYYYYYYYYYYYYYYY")
   var VOctoprintPrinterState = transform("JSONPATH", "$.current.state", JOctoprintPrinterState)
   OctoprintPrinterState.postUpdate(VOctoprintPrinterState)

   var VOctoprintPrinterProfile = transform("JSONPATH", "$.current.printerProfile", JOctoprintPrinterState)
   OctoprintPrinterProfile.postUpdate(VOctoprintPrinterProfile)

	if (VOctoprintPrinterState != "Closed")
	    {
		if (VOctoprintPrinterState == "Printing")
			{
			var String JOctoprintJob = sendHttpGetRequest("http://xxx.xxx.xxx.xxx/api/job?apikey=YYYYYYYYYYYYYYYYYYYYYY")
			var VOctoprintJobEstimatedPrintTime = transform("JSONPATH", "$.progress.printTimeLeft", JOctoprintJob)
			OctoprintJobEstimatedPrintTime.postUpdate(VOctoprintJobEstimatedPrintTime)

			var VOctoprintJobFileName = transform("JSONPATH", "$.job.file.name", JOctoprintJob)
			OctoprintJobFileName.postUpdate(VOctoprintJobFileName)

			var VOctoprintJobProgressCompletion = transform("JSONPATH", "$.progress.completion", JOctoprintJob)
			OctoprintJobProgressCompletion.postUpdate(VOctoprintJobProgressCompletion)
	
			var VOctoprintJobPrintTimeLeft = transform("JSONPATH", "$.progress.printTime", JOctoprintJob)
			OctoprintJobPrintTimeLeft.postUpdate(VOctoprintJobPrintTimeLeft)
			}


		var String JOctoprintPrinter = sendHttpGetRequest("http://xxx.xxx.xxx.xxx/api/printer?apikey=YYYYYYYYYYYYYYYYYYYYYY")
			var VOctoprintPrinterPrintingState = transform("JSONPATH", "$.state.text", JOctoprintPrinter)
			OctoprintPrinterPrintingState.postUpdate(VOctoprintPrinterPrintingState)

			var VOctoprintPrinterHotEndTemp = transform("JSONPATH", "$.temperature.tool0.actual", JOctoprintPrinter)
			OctoprintPrinterHotEndTemp.postUpdate(VOctoprintPrinterHotEndTemp)

			var VOctoprintPrinterHotEndTempTarget = transform("JSONPATH", "$.temperature.tool0.target", JOctoprintPrinter)
			OctoprintPrinterHotEndTempTarget.postUpdate(VOctoprintPrinterHotEndTempTarget)

			var VOctoprintPrinterBedTemp = transform("JSONPATH", "$.temperature.bed.actual", JOctoprintPrinter)
			OctoprintPrinterBedTemp.postUpdate(VOctoprintPrinterBedTemp)

			var VOctoprintPrinterBedTempTarget = transform("JSONPATH", "$.temperature.bed.actual", JOctoprintPrinter)
			OctoprintPrinterBedTempTarget.postUpdate(VOctoprintPrinterBedTempTarget)
	    }

end

I am getting a lot of the following messages:

    2019-11-19 08:27:51.241 [WARN ] [ab.binding.http.internal.HttpBinding] - Transformation 'JSONPATH($.temperature.tool0.target)' threw an exception. [response={
  "sd": {

    "ready": false

  }, 

  "state": {

    "flags": {

      "cancelling": false, 

      "closedOrError": false, 

      "error": false, 

      "finishing": false, 

      "operational": true, 

      "paused": false, 

      "pausing": false, 

      "printing": false, 

      "ready": true, 

      "resuming": false, 

      "sdReady": false

    }, 

    "text": "Operational"

  }, 

  "temperature": {

    "bed": {

      "actual": null, 

      "offset": 0, 

      "target": 0.0

    }

  }

}

]

    2019-11-19 08:27:51.504 [WARN ] [ab.binding.http.internal.HttpBinding] - Transformation 'JSONPATH($.temperature.tool0.actual)' threw an exception. [response={

    2019-11-19 08:28:52.146 [WARN ] [ab.binding.http.internal.HttpBinding] - Transformation 'JSONPATH($.temperature.tool0.target)' threw an exception. [response={

    2019-11-19 08:28:52.401 [WARN ] [ab.binding.http.internal.HttpBinding] - Transformation 'JSONPATH($.temperature.tool0.actual)' threw an exception. [response={

    2019-11-19 08:29:53.019 [WARN ] [ab.binding.http.internal.HttpBinding] - Transformation 'JSONPATH($.temperature.tool0.target)' threw an exception. [response={

    2019-11-19 08:29:53.272 [WARN ] [ab.binding.http.internal.HttpBinding] - Transformation 'JSONPATH($.temperature.tool0.actual)' threw an exception. [response={

    2019-11-19 08:30:53.960 [WARN ] [ab.binding.http.internal.HttpBinding] - Transformation 'JSONPATH($.temperature.tool0.target)' threw an exception. [response={

    2019-11-19 08:30:54.242 [WARN ] [ab.binding.http.internal.HttpBinding] - Transformation 'JSONPATH($.temperature.tool0.actual)' threw an exception. [response={

I have removed the responses since it was too big to post. I have OctoPrint Version 1.3.12

For OH3 with the new http binding:
Items

// Octoprint
Group gOctoprint "Octoprint" (gAll)

String OctoprintPrinterState			"State [%s]"					                				(gOctoprint)	{channel="http:url:printer-connection:current_state"}
String OctoprintPrinterProfile			"Profile [%s]"					                                (gOctoprint)	{channel="http:url:printer-connection:printerProfile"}

String OctoprintPrinterCommand          "Printer Command"                                               (gOctoprint) 
String OctoprintSystemCommand           "System Command"                                                (gOctoprint) 

Number OctoprintJobEstimatedPrintTime	"Estimated Print Time [%.0f s]"	                <time>          (gOctoprint)	{channel="http:url:printer-job:estimatedPrintTime"}
String OctoprintJobFileName				"Filename [%s]"					                <text>          (gOctoprint)	{channel="http:url:printer-job:filename"}
Number OctoprintJobProgressCompletion	"Completion [%.0f %%]"					        <battery>       (gOctoprint)	{channel="http:url:printer-job:progress"}
Number OctoprintJobPrintTime			"Time Printed [%.0f s]"			                <time>	        (gOctoprint)	{channel="http:url:printer-job:printTime"}
String OctoprintJobPrintTimeString		"Time Printed [%s]"			                    <time>	        (gOctoprint)	
Number OctoprintJobPrintTimeLeft		"Time Left [%.0f s]"			                <time>	        (gOctoprint)	{channel="http:url:printer-job:printTimeLeft"}
String OctoprintJobPrintTimeLeftString  "Time Left [%s]"			                    <time>	        (gOctoprint)    
String OctoprintJobPrintETAString       "ETA [%s]"			                            <time>	        (gOctoprint)    
DateTime OctoprintJobPrintETADateTime   "ETA [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]"    <time>          (gOctoprint)

String OctoprintPrinterPrintingState    "Printing State [%s]"								    		(gOctoprint)    {channel="http:url:printer-info:state"}
Number OctoprintPrinterHotEndTemp		"Nozzle temp [%.1f °C]"		                    <temperature>	(gOctoprint)	{channel="http:url:printer-info:temperature_bed_actual"}
Number OctoprintPrinterHotEndTempTarget	"Nozzle target [%.1f °C]"	                    <temperature>	(gOctoprint)	{channel="http:url:printer-info:temperature_bed_target"}
Number OctoprintPrinterBedTemp			"Bed temp [%.1f °C]"		                    <temperature>	(gOctoprint)	{channel="http:url:printer-info:temperature_hotend_actual"}
Number OctoprintPrinterBedTempTarget	"Bed target [%.1f °C]"							<temperature>	(gOctoprint)	{channel="http:url:printer-info:temperature_hotend_target"}

http.things

Thing http:url:printer-connection "3D Printer Connection" [ baseURL="http://octopi.yourdomain/api/connection?apikey=YOURAPIKEY", refresh=60] {
    Channels:
        Type string : current_state "Current State" [ stateTransformation="JSONPATH:$.current.state" ]
		Type string : printerProfile "Printer Profile" [ stateTransformation="JSONPATH:$.current.printerProfile" ]
}

Thing http:url:printer-job "3D Printer Print Job" [ baseURL="http://octopi.yourdomain/api/job?apikey=YOURAPIKEY", refresh=60] {
    Channels:
        Type number : estimatedPrintTime "Estimated Print Time" [ stateTransformation="JSONPATH:$.job.estimatedPrintTime" ]
		Type string : filename "Filename" [ stateTransformation="JSONPATH:$.job.file.name" ]
		Type number : filesize "Filesize" [ stateTransformation="JSONPATH:$.job.file.size" ]
		Type number : progress "Progress" [ stateTransformation="JSONPATH:$.progress.completion" ]
		Type number : filepos "Printed" [ stateTransformation="JSONPATH:$.progress.filepos" ]
		Type number : printTime "Time Printed" [ stateTransformation="JSONPATH:$.progress.printTime" ]
		Type number : printTimeLeft "Time Left" [ stateTransformation="JSONPATH:$.progress.printTimeLeft" ]
}

Thing http:url:printer-info "3D Printer Info" [ baseURL="http://octopi.yourdomain/api/printer?apikey=YOURAPIKEY", refresh=60] {
    Channels:
        Type string : state "Printing State" [ stateTransformation="JSONPATH:$.state.text" ]
		Type number : temperature_bed_actual "Temperature Bed Actual" [ stateTransformation="JSONPATH:$.temperature.tool0.actual" ]
		Type number : temperature_bed_target "Temperature Bed Target" [ stateTransformation="JSONPATH:$.temperature.tool0.target" ]
		Type number : temperature_hotend_actual "Temperature Hotend Actual" [ stateTransformation="JSONPATH:$.temperature.bed.actual" ]
		Type number : temperature_hotend_target "Temperature Hotend Target" [ stateTransformation="JSONPATH:$.temperature.bed.target" ]
}

3 Likes

The Rule #2 (Time Left String) doesnt matter with OpenHAB 3. Can someone define the Rule #2 für Openhab 3?

Thanks, Cool!

I think there is a small typo in the item file:

should be

String OctoprintPrinterPrintingState    "Printing State [%s]"								    		(gOctoprint)    {channel="http:url:printer-info:state"}
1 Like

Your absolutly right!
Didn’t notice it till yesterday, forgot to update it here, will do now, thanks!

Does anyone have a OH3 widget displaying the webcam feed from Octoprint? I haven’t been able to get the right combination of things to make it work. I’m not doing much with video in my automations right now…

I figured it out. Was trying to do it as a video instead of an image, using just the URL from the feed.

Also, note that in the thing definition above, the tool0 and bed temperatures are swapped…

And lastly, is there a graceful way to suppress the errors that the thing generates when the printer is turned off? I’m going to look into disabling the thing when the rule turns off the printer.

You can also use the ipcamera binding to integrate the camera!

1 Like

How do you get octopi to work with the ipcamera binding? Wasn’t able to integrate it by now via this way.

can we shutdown the octopi server through oh3?

FYI, someone (maybe in this thread?) has produced an OH3 plugin for octoPrint, so that you can power on a 3D printer automatically when you upload a file to octoPrint, or turn it off when it’s idle. This was possible with MQTT before, but it’ll now communicate directly with OH3 over REST with an API token.

I couldn’t get the plugin to work at first, but it turned out that my octoPrint server (an RPi3) can’t resolve the hostname of my openHAB server (an RPi4). It worked immediately when I substituted in my IP address.

1 Like