Hi all,
I succeeded getting the status of my 3D Printer via MQTT (OH MQTT 2.4) which is controlled by Octoprint on a Raspberry Pi.
This is maybe a more elegant implementation than the one over HTTP/REST I shared earlier but lacks the commanding part:
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)
}
}
ToDo:
- See if it is possible to issue commands over MQTT as well
Enjoy!