Since Octoprint is hardly the optimal UI in this day and age, I’ve changed to using Moonraker and interfaces based on that. This means some parts of my Home Assistant configuration had to change.
Update: Moonraker stores preview images now – a comment describes a cleaner way to achieve the same end result.
This is how I got the STL preview embedded in gcode from the Klipper websocket service Moonraker to Home Assistant. Everything assumes your Klipper and Moonraker already work as intended.
Here’s the whole printer info code, and another sensor that extracts all the metadata from print preview. Note this takes the full size image, as my slicer generates a smaller thumbnail too. Be sure the json attributes path matches your slicer – this should be good for slic3r variants such as SuperSlicer. Big thanks to Arksine for the example. Take note of the number of thumbnail sizes your slicer creates – this sensor takes the 2nd preview image generated.
#sensors.yaml - platform: rest name: spaghetti_sensor resource: "http://192.168.1.20:7125/printer/objects/query?heater_bed&extruder&print_stats&toolhead&display_status&virtual_sdcard" json_attributes_path: "$.result.status" json_attributes: - heater_bed - extruder - print_stats - toolhead - display_status - virtual_sdcard value_template: 'OK' - platform: template sensors: spaghetti_hotend_target: friendly_name: 'Hotend Target' value_template: '{{ states.sensor.spaghetti_sensor.attributes["extruder"]["target"] | float | round(1) }}' device_class: temperature unit_of_measurement: '°C' icon_template: mdi:thermometer spaghetti_hotend_actual: friendly_name: 'Hotend Actual' value_template: '{{ states.sensor.spaghetti_sensor.attributes["extruder"]["temperature"] | float | round(1) }}' device_class: temperature unit_of_measurement: '°C' icon_template: mdi:thermometer spaghetti_bed_target: friendly_name: 'Bed Target' value_template: '{{ states.sensor.spaghetti_sensor.attributes["heater_bed"]["target"] | float | round(1) }}' device_class: temperature unit_of_measurement: '°C' icon_template: mdi:thermometer spaghetti_bed_actual: friendly_name: 'Bed Actual' value_template: '{{ states.sensor.spaghetti_sensor.attributes["heater_bed"]["temperature"] | float | round(1) }}' device_class: temperature unit_of_measurement: '°C' icon_template: mdi:thermometer spaghetti_state: friendly_name: 'Printer State' value_template: '{{ states.sensor.spaghetti_sensor.attributes["print_stats"]["state"]}}' icon_template: > {% set val = states.sensor.spaghetti_sensor.attributes["print_stats"]["state"] %} {% if val == 'standby' %} mdi:sleep {% elif val == 'error' %} mdi:alert-circle {% elif val == 'printing' %} mdi:printer-3d-nozzle {% elif val == 'paused' %} mdi:pause-circle {% elif val == 'complete' %} mdi:printer-3d {% else %} mdi:help-circle {% endif %} spaghetti_current_print: friendly_name: 'Current Print' value_template: '{{ states.sensor.spaghetti_sensor.attributes["print_stats"]["filename"]}}' spaghetti_current_progress: friendly_name: 'Progress' value_template: '{{ ((states.sensor.spaghetti_sensor.attributes["display_status"]["progress"])*100) | round(0, "floor") }}' unit_of_measurement: '%' icon_template: mdi:progress-clock spaghetti_print_time: friendly_name: 'Time Elapsed' value_template: '{{ states.sensor.spaghetti_sensor.attributes["print_stats"]["print_duration"] |timestamp_custom("%H:%M:%S", 0)}}' icon_template: mdi:camera-timer spaghetti_time_remaining: friendly_name: 'Time Remaining' value_template: '{{ (((states.sensor.spaghetti_sensor.attributes["print_stats"]["print_duration"]/states.sensor.spaghetti_sensor.attributes["display_status"]["progress"]- states.sensor.spaghetti_sensor.attributes["print_stats"]["print_duration"]) if states.sensor.spaghetti_sensor.attributes["display_status"]["progress"]>0 else 0)) | timestamp_custom("%H:%M:%S", 0)}}' icon_template: mdi:timer-sand spaghetti_eta: friendly_name: 'ETA' value_template: '{{ (as_timestamp(now())+2*60*60+((states.sensor.spaghetti_sensor.attributes["print_stats"]["print_duration"]/states.sensor.spaghetti_sensor.attributes["display_status"]["progress"]- states.sensor.spaghetti_sensor.attributes["print_stats"]["print_duration"]) if states.sensor.spaghetti_sensor.attributes["display_status"]["progress"]>0 else 0)) | timestamp_custom("%H:%M:%S", 0)}}' icon_template: mdi:av-timer spaghetti_nozzletemp: friendly_name: 'Nozzle Temperature' value_template: '{{[( states.sensor.spaghetti_sensor.attributes["extruder"]["temperature"] | float | round(1)| string)," / ",( states.sensor.spaghetti_sensor.attributes["extruder"]["target"] | float | round(1)| string)]|join}}' icon_template: mdi:thermometer spaghetti_bedtemp: friendly_name: 'Bed Temperature' value_template: '{{[( states.sensor.spaghetti_sensor.attributes["heater_bed"]["temperature"] | float | round(1)| string)," / ",( states.sensor.spaghetti_sensor.attributes["heater_bed"]["target"] | float | round(1)| string)]|join}}' icon_template: mdi:thermometer
04/03/2021: Updated this camera entity to properly display the placeholder image
#cameras.yaml - platform: generic name: klipper_gcode_preview still_image_url: > {% if states.sensor.spaghetti_state.state == 'standby' %} https://foo.bar.org:8123/local/placeholder.png {% elif states.sensor.spaghetti_state.state == 'complete' %} https://foo.bar.org:8123/local/placeholder.png {% elif states.sensor.spaghetti_state.state == 'unknown' %} https://foo.bar.org:8123/local/placeholder.png {% else %} http://192.168.1.20:7125/server/files/gcodes/.thumbs/{{ states.sensor.spaghetti_sensor.attributes['print_stats']['filename'][:-6]}}-250x250.png {% endif %} scan_interval: 5 content_type: image/png verify_ssl: false
Thank you for this, it helped me a lot setting things up in HomeAssistant.
It’s possible to load the gcode thumbnail directly from the Klipper/Moonraker host when your slicer provides the thumbnail, no need for the python script and automation.
There might be a better way, I’m no expert, but this worked for me 🙂
1. Remove ‘.gcode’ from filename
In sensors.yaml for ‘current_print’ sensor:
value_template: ‘{{ states.sensor.spaghetti_sensor.attributes[“print_stats”][“filename”][:-6]}}’
2. Use filename to load gcode preview thumbnail directly from Klipper host
In cameras.yaml for ‘klipper_gcode_preview’ camera:
still_image_url: http://192.168.1.20/server/files/gcodes/.thumbs/{{ states((‘sensor.spaghetti_current_print’)) }}-400×300.png
Thanks for the comment. Moonraker indeed added that feature some months after this writeup, and what you describe is pretty much the current best practise.
Anyone reading this and have problem (I had huge problem to implement that. This is my solution.
1)
in ((‘sensor.spaghetti_current_print’)) you need to change ‘’ to ”
and the second one … much more tricky
2) in 400×300.png you need to change x. I don’t know to what other letter (it look like x but it apparently is different letter) just go to your klipper right-click on stl preview and copy image address. Pase it to notepad and copy-paste x with x in 400×300.png
It looks almost identical but it is different. Took me ages to solve this. Hope someone will found it helpfull.
Hi there,
Thank you for this i have finally found something that worked ,just wondering if the updated cleaner way of getting the stl preview has been added to your code now or do i have to change that still please.
Yes, the camera template could be neater but all of it technically works with an up to date klipper / moonraker installation, given that you adjust IPs and addresses to match your system.