Press "Enter" to skip to content

Prusa Octoprint Status via MQTT in Openhab

bist 0

What you need:

  • openHAB2
  • New MQTT Binding installed in OH2 (aka MQTT 2.4)
  • JSONPATH Transformation installed in OH2
  • Octoprint running with MQTT Plugin (minimum v0.8.0) installed

In Octoprint, go to Settings -> MQTT and configure your broker and Topics (I basically activated everything, temperature with 1°C setting)

Create a new *.things file (e.g. octoprint.things) and put the following mqtt-things:
Make sure you have already configured your MQTT broker connection from OH2!

Thing mqtt:topic:octoprint "Octoprint MQTT" (mqtt:broker:127_0_0_1_1883) {
    Channels:
        Type string : connected "Connected" [ stateTopic="octoPrint/mqtt" ]
        Type string : state "State" [ stateTopic="octoPrint/event/PrinterStateChanged", transformationPattern="JSONPATH:$.state_string" ]
        Type string : event "Event" [ stateTopic="octoPrint/event/+", transformationPattern="JSONPATH:$._event" ]
        Type string : filename "Filename" [ stateTopic="octoPrint/progress/printing", transformationPattern="JSONPATH:$.printer_data.job.file.name" ]
        Type number : progress "Progress" [ stateTopic="octoPrint/progress/printing", transformationPattern="JSONPATH:$.printer_data.progress.completion" ]
        Type number : printTime "Time Printed" [ stateTopic="octoPrint/progress/printing", transformationPattern="JSONPATH:$.printer_data.progress.printTime" ]
        Type number : printTimeLeft "Time Left" [ stateTopic="octoPrint/progress/printing", transformationPattern="JSONPATH:$.printer_data.progress.printTimeLeft" ]
        Type number : layerheight "Layerheight" [ stateTopic="octoPrint/progress/printing", transformationPattern="JSONPATH:$.printer_data.currentZ" ]
        Type number : temperature_bed_actual "Temperature Bed Actual" [ stateTopic="octoPrint/temperature/bed", transformationPattern="JSONPATH:$.actual" ]
        Type number : temperature_bed_target "Temperature Bed Target" [ stateTopic="octoPrint/temperature/bed", transformationPattern="JSONPATH:$.target" ]
        Type number : temperature_hotend_actual "Temperature Hotend Actual" [ stateTopic="octoPrint/temperature/tool0", transformationPattern="JSONPATH:$.actual" ]
        Type number : temperature_hotend_target "Temperature Hotend Target" [ stateTopic="octoPrint/temperature/tool0", transformationPattern="JSONPATH:$.target" ]
}

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

Group gOctoprint "Octoprint" (gAll)

// MQTT
String OctoprintConnected                           "Connected [%s]"		    <network>       (gOctoprint)    {channel="mqtt:topic:octoprint:connected"} 
String OctoprintState	                            "State [%s]"		        <office>        (gOctoprint)	{channel="mqtt:topic:octoprint:state"}
String OctoprintEvent   	                        "Event [%s]"		        <office>        (gOctoprint)	{channel="mqtt:topic:octoprint:event"}
String OctoprintJobFileName	                        "Filename [%s]"		        <office>        (gOctoprint)	{channel="mqtt:topic:octoprint:filename"}
Number:Dimensionless OctoprintJobProgressCompletion	"Completion [%.0f %%]"	    <battery>       (gOctoprint)	{channel="mqtt:topic:octoprint:progress"}
Number OctoprintPrintTime                           "Time Printed [%.0f s]"	    <time>          (gOctoprint)	{channel="mqtt:topic:octoprint:printTime"}
String OctoprintPrintTimeString                     "Time Printed [%s]"	        <time>          (gOctoprint)
Number OctoprintPrintTimeLeft                       "Time Left [%.0f s]"	    <time>          (gOctoprint)	{channel="mqtt:topic:octoprint:printTimeLeft"}
String OctoprintPrintTimeLeftString                 "Time Left [%s]"	        <time>          (gOctoprint)
String OctoprintPrintETAString                      "ETA [%s]"			                            <time>	        (gOctoprint)    
DateTime OctoprintPrintETADateTime                  "ETA [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]"    <time>          (gOctoprint)

Number:Length OctoprintJobCurrentLayerHeight        "Layer Height [%.1f mm]"    <flowpipe>      (gOctoprint)    {channel="mqtt:topic:octoprint:layerheight"}

Number:Temperature OctoprintPrinterHotEndTemp		"Nozzle temp [%.1f °C]"     <temperature>   (gOctoprint)	{channel="mqtt:topic:octoprint:temperature-hotend-actual"} 
Number:Temperature OctoprintPrinterHotEndTempTarget	"Nozzle target [%.1f °C]"   <temperature>	(gOctoprint)	{channel="mqtt:topic:octoprint:temperature-hotend-target"} 
Number:Temperature OctoprintPrinterBedTemp			"Bed temp [%.1f °C]"        <temperature>	(gOctoprint)	{channel="mqtt:topic:octoprint:temperature-bed-actual"} 
Number:Temperature OctoprintPrinterBedTempTarget	"Bed target [%.1f °C]"      <temperature>	(gOctoprint)	{channel="mqtt:topic:octoprint:temperature-bed-target"}

Switch OctoprintPower                               "Power"                                     (gOctoprint)    {channel="mqtt:topic:sonoff-plug-1:power"}
Switch OctoprintShutdownAfterPrint                  "Turn Off after Print"                      (gOctoprint)

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

rule "Time Printed String"
when
	Item OctoprintPrintTime changed
then
    val seconds = (OctoprintPrintTime.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)
    OctoprintPrintTimeString.postUpdate(formattedTime)
end

rule "Time Left String"
when
	Item OctoprintPrintTimeLeft changed
then
    val seconds = (OctoprintPrintTimeLeft.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)
    OctoprintPrintTimeLeftString.postUpdate(formattedTime)

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

end

rule "Shutdown after finish"
when
    Item OctoprintState changed from Printing to Operational
then
	if (OctoprintShutdownAfterPrint.state == ON && OctoprintJobProgressCompletion.state == 100){
		createTimer(now.plusSeconds(60),  [ |
            sendCommand(OctoprintPower, OFF)
        ])
        
        createTimer(now.plusSeconds(70),  [ |
            sendCommand(OctoprintShutdownAfterPrint, OFF)
        ])
	}
end

Example Sitemap:

Text label="3D Printer" icon="3dprinter" {
		Text	item=OctoprintState
		Text	item=OctoprintEvent
		Text	item=OctoprintJobFileName
		Text	item=OctoprintPrintTimeString
		Text	item=OctoprintPrintTimeLeftString
		Text	item=OctoprintPrintETADateTime
		Text	item=OctoprintJobProgressCompletion
		Text	item=OctoprintJobCurrentLayerHeight
		Text	item=OctoprintPrinterHotEndTemp
		Text	item=OctoprintPrinterBedTemp
		Image	url="http://octopi.local:8080/?action=snapshot" refresh=30000 // Camera Feed if you have
		Chart 	item=OctoprintJobProgressCompletion refresh=600000 period=12h // Plot progress over last 12h
		Text label="Power" {
			Switch 	item=OctoprintPower // Hidden On-Off Plug I use (to not accidentally click it)
		}
	}

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.