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

rest
openhab2
http
Tags: #<Tag:0x00007f015a08c200> #<Tag:0x00007f015a08cd18> #<Tag:0x00007f015a08e398>

(David K.) #1

Hi all,

I succeeded getting the status of my 3D Printer which is controlled by Octoprint on a Raspberry Pi.

What you need:

  • openHab2
  • HTTP Binding installed in OH2
  • JSONPATH Transformation installed in OH2
  • Octoprint installed

In Octoprint, go to Settings -> API. Enable API and CORS. Note down your API KEY.

Create a new *.items file (e.g. octoprint.items) and put the following code:

  • Replace “octopi.yourdomain” with what you type into your browser to access Octoprint
  • Replace “YOURAPIKEY” with your API KEY from the Octoprint front-end.

Create a new *.rules file (e.g. octoprint.rules) and put the follwing code:

  • Replace “octopi.yourdomain” with what you type into your browser to access Octoprint
  • Replace “YOURAPIKEY” with your API KEY from the Octoprint front-end.

A lot more commands could be added, the API is documented here: http://docs.octoprint.org/en/master/api/index.html

The “10000” in the HTTP item means it will pull new data every 10000ms or 10 seconds.
The JSONPATH command converts the JSON message into what you really need.

Enjoy!

// Octoprint
Group gOctoprint "Octoprint" (gAll)

String OctoprintPrinterState			"State [%s]"					                                (gOctoprint)	{http="<[http://octopi.yourdomain/api/connection?apikey=YOURAPIKEY:60000:JSONPATH($.current.state)]"}
String OctoprintPrinterProfile			"Profile [%s]"					                                (gOctoprint)	{http="<[http://octopi.yourdomain/api/connection?apikey=YOURAPIKEY:60000:JSONPATH($.current.printerProfile)]"}

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

Number OctoprintJobEstimatedPrintTime	"Estimated Print Time [%.0f s]"	                <time>          (gOctoprint)	{http="<[http://octopi.yourdomain/api/job?apikey=YOURAPIKEY:60000:JSONPATH($.job.estimatedPrintTime)]"}
String OctoprintJobFileName				"Filename [%s]"					                                (gOctoprint)	{http="<[http://octopi.yourdomain/api/job?apikey=YOURAPIKEY:60000:JSONPATH($.job.file.name)]"}
Number OctoprintJobProgressCompletion	"Completion [%.0f %%]"					        <battery>       (gOctoprint)	{http="<[http://octopi.yourdomain/api/job?apikey=YOURAPIKEY:60000:JSONPATH($.progress.completion)]"}
Number OctoprintJobPrintTime			"Time Printed [%.0f s]"			                <time>	        (gOctoprint)	{http="<[http://octopi.yourdomain/api/job?apikey=YOURAPIKEY:60000:JSONPATH($.progress.printTime)]"}
String OctoprintJobPrintTimeString		"Time Printed [%s]"			                    <time>	        (gOctoprint)	
Number OctoprintJobPrintTimeLeft		"Time Left [%.0f s]"			                <time>	        (gOctoprint)	{http="<[http://octopi.yourdomain/api/job?apikey=YOURAPIKEY:60000:JSONPATH($.progress.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    "State [%s]"								                    (gOctoprint)    {http="<[http://octopi.yourdomain/api/printer?apikey=YOURAPIKEY:60000:JSONPATH($.state.text)]"}
Number OctoprintPrinterHotEndTemp		"Nozzle temp [%.1f °C]"		                    <temperature>	(gOctoprint)	{http="<[http://octopi.yourdomain/api/printer?apikey=YOURAPIKEY:60000:JSONPATH($.temperature.tool0.actual)]"}
Number OctoprintPrinterHotEndTempTarget	"Nozzle target [%.1f °C]"	                    <temperature>	(gOctoprint)	{http="<[http://octopi.yourdomain/api/printer?apikey=YOURAPIKEY:60000:JSONPATH($.temperature.tool0.target)]"}
Number OctoprintPrinterBedTemp			"Bed temp [%.1f °C]"		                    <temperature>	(gOctoprint)	{http="<[http://octopi.yourdomain/api/printer?apikey=YOURAPIKEY:60000:JSONPATH($.temperature.bed.actual)]"}
Number OctoprintPrinterBedTempTarget	"Bed target [%.1f °C]"		                    <temperature>	(gOctoprint)	{http="<[http://octopi.yourdomain/api/printer?apikey=YOURAPIKEY:60000:JSONPATH($.temperature.bed.target)]"}

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://octopi.yourdomain/api/job?apikey=YOURAPIKEY"
    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://octopi.yourdomain/api/system/commands/core/' + OctoprintSystemCommand.state + '?apikey=YOURAPIKEY'
    //var contenttype = "application/json"

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



Receiving data into OH2 items from other device via REST API
3D Printer Binding?
3d printer api doesn't work
(Bofh90) #2

Perfect, it worked after installing the “JSONPath Transformation”. Maybe you can add this to your inital Post as a requirement. Thank you =)


(Betafritz) #3

I can´t get it to work.
the http binding and jasonpath is installed.
in the browser, I get some json data with e.g. http://192.168.178.22/api/printer?apikey=****[...]. so, the communication from the octoprint should be fine. but on the openhab side it´s not working.
In the items file, I used the same items as above but with “http=”<[http://192.168.178.22/api[...]"
Does anybody have an idea what could be wrong?


(David K.) #4

Hi all,

some time has passed and the Octoprint API has changed. I have updated the first post with the new configuration.

Also, I’ve added commanding of the most basic things: Job operations (start,cancel,pause) as well as system commands (shutdown,reboot).

Enjoy!


(Norbert Schnitzler) #5

Hi @SpaceGlider,

really cool example. It worked out-of-the-box for me except the calculated values from the rules. They seems not to be executed and not showing errors.

Do you have an idea, how to solve this?

thanks in advance!

Norbert


(David K.) #6

Have you started a print? The values will only be calculated once they are being updated. For me this is usually about a few minutes into a print (or after the first layer?).

Maybe you changed item names? Otherwise no idea what could be wrong, as I copy-pasted it from my setup.

Cheers
David


(Norbert Schnitzler) #7

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


(David K.) #8

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

(Norbert Schnitzler) #9

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.


(David K.) #10

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.


(JustAProgrammer) #11

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

(Constantinos Contis) #12

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]