Hi all!
This summer I decided to skip OctoPrint and use PrusaLink / Prusa Connect instead.
My reason for going from OctoPrint to PrusaLink / Prusa Connect is mainly because I want to keep my setup simple and reliable. The integration with PrusaLink / Prusa Connect, PrusaSlicer and https://www.printables.com/ works so nice. Here is a brief comparison:
OctoPrint pros
- Many features and plugins (firmware update, bed leveling)
- Supports streaming USB camera
OctoPrint cons
- Needs constant tinkering
- Needs total reinstall when OctoPi upgrades
- Old and ugly gui
- Missing some sensors in Home Assistant
- No auto reconnect when powering off printer
PrusaLink / PrusaConnect pros
- Minimal maintenance and configuration. Just install and use
- Made by Prusa. Works well with PrusaSlicer, Prusa-printer and printables.com
- Nice gui and features
PrusaLink / Prusa Connect cons
- No plugins like OctoPrint
- No integration for Home Assistant
I followed this guide for installing PrusaLink Web 0.7.0 on a Raspberry Pi3 with USB connection to my printer. Then I installed the PrusaLink integration in Home Assistant and found out this:
After some digging I found out that the integration PrusaLink only works for embedded PrusaLink in newer 32-bit “Buddy” printers. Not with PrusaLink Web installed on a Pi.
https://community.home-assistant.io/t/prusa-3d-printers-support/550070
https://github.com/home-assistant/core/issues/95529#issuecomment-1666508663
I don’t have the time to learn how to make PrusaLink integration work for my printer. So I spent some time making my own sensors, entities card and automation and want to share it with you.
When digging in the code for integration PrusaLink I found out that legacy API was used, not the new API v1 that is preferred by Prusa. There is mainly two endpoints using curl:
curl ‘http://prusalink.local/api/v1/status’ --digest -u username:password| json_pp
curl ‘http://prusalink.local/api/v1/job’ --digest -u username:password| json_pp
API-key is still supported but HTTP Digest Access Authentication is preferred as secrets is encrypted.
This was my idea from the beginning without knowing if it’s possible or not:
Sensors:
- Printer Status
- Nozzle Temperature
- Nozzle Target Temperature
- Heatbed Temperature
- Heatbed Target Temperature
- Print Speed
- Z Height
- Fan Hotend Speed
- Fan Print Speed
- Filename
- Filament
- Progress
- Estimated Print Time
- Time Printing
- Time Remaining
Command buttons:
- Cancel
- Pause
- Resume
- Home
- Z Up
Automations:
- Send notification when print is done
- Send notification some time before print is done
- Send notification when error occurs
Camera/Picture:
- View snapshots from camera
- View thumbnail from gcode
- View live camera feed from camera connected to PrusaLink
This is my solution so far. Entities card first:
entities:
- entity: sensor.3d_printer_status
name: Printer Status
- entity: sensor.3d_printer_nozzle_temperature
name: Nozzle Temperature
- entity: sensor.3d_printer_nozzle_target_temperature
name: Nozzle Target Temperature
- entity: sensor.3d_printer_heatbed_temperature
name: Heatbed Temperature
- entity: sensor.3d_printer_heatbed_target_temperature
name: Heatbed Target Temperature
- entity: sensor.3d_printer_print_speed
name: Print Speed
- entity: sensor.3d_printer_z_height
name: Z Height
- entity: sensor.3d_printer_fan_hotend_speed
name: Fan Hotend Speed
- entity: sensor.3d_printer_fan_print_speed
name: Fan Print Speed
- type: divider
- entity: sensor.3d_printer_filename
name: Filename
- entity: sensor.3d_printer_filament
name: Filament
- entity: sensor.3d_printer_progress
name: Progress
- entity: sensor.3d_printer_estimated_print_time
name: Estimated Print Time
- entity: sensor.3d_printer_time_printing
name: Time Printing
- entity: sensor.3d_printer_time_remaining
name: Time Remaining
title: Prusa i3 MK3S+
state_color: true
And the RESTful sensors in configuration.yaml
rest:
- resource: http://prusalink.local/api/v1/status
authentication: digest
username: !secret prusalink_username
password: !secret prusalink_password
scan_interval: 30
sensor:
- name: "3D-Printer Status"
value_template: "{{ value_json.printer.state }}"
icon: "mdi:printer-3d"
- name: "3D-Printer Nozzle Temperature"
value_template: "{{ value_json.printer.temp_nozzle }}"
device_class: temperature
unit_of_measurement: "°C"
icon: "mdi:printer-3d-nozzle-heat"
- name: "3D-Printer Nozzle Target Temperature"
value_template: "{{ value_json.printer.target_nozzle }}"
device_class: temperature
unit_of_measurement: "°C"
icon: "mdi:printer-3d-nozzle-heat"
- name: "3D-Printer Heatbed Temperature"
value_template: "{{ value_json.printer.temp_bed }}"
device_class: temperature
unit_of_measurement: "°C"
icon: "mdi:radiator"
- name: "3D-Printer Heatbed Target Temperature"
value_template: "{{ value_json.printer.target_bed }}"
device_class: temperature
unit_of_measurement: "°C"
icon: "mdi:radiator"
- name: "3D-Printer Z Height"
value_template: "{{ value_json.printer.axis_z }}"
device_class: distance
unit_of_measurement: "mm"
icon: "mdi:arrow-up-down"
- name: "3D-Printer Print Speed"
value_template: "{{ value_json.printer.speed }}"
unit_of_measurement: "%"
icon: "mdi:speedometer"
- name: "3D-Printer Fan Hotend Speed"
value_template: "{{ value_json.printer.fan_hotend }}"
unit_of_measurement: "rpm"
icon: "mdi:fan"
- name: "3D-Printer Fan Print Speed"
value_template: "{{ value_json.printer.fan_print }}"
unit_of_measurement: "rpm"
icon: "mdi:fan"
- resource: http://prusalink.local/api/v1/job
authentication: digest
username: !secret prusalink_username
password: !secret prusalink_password
scan_interval: 10
sensor:
- name: "3D-Printer Filename"
value_template: "{{ value_json.file.name if value_json.state=='PRINTING' else None }}"
icon: "mdi:file-image-outline"
- name: "3D-Printer Filament"
value_template: "{{ value_json.file.meta.filament_type if value_json.state=='PRINTING' else None }}"
icon: "mdi:palette-swatch-variant"
- name: "3D-Printer Progress"
value_template: "{{ value_json.progress | round (0) }}"
unit_of_measurement: "%"
icon: "mdi:timer-sand"
- name: "3D-Printer Estimated Print Time"
value_template: " {{ timedelta(seconds=value_json.file.meta.estimated_print_time) if value_json.state=='PRINTING' else None }}"
icon: "mdi:timer-sand-complete"
- name: "3D-Printer Time Printing"
value_template: "{{ timedelta(seconds=value_json.time_printing) if value_json.state=='PRINTING' else None }}"
icon: "mdi:clock-start"
- name: "3D-Printer Time Remaining"
value_template: "{{ timedelta(seconds=value_json.time_remaining) if value_json.state=='PRINTING' else None }}"
icon: "mdi:clock-end"
Command buttons in horizontal stack card:
type: horizontal-stack
cards:
- show_name: true
show_icon: true
type: button
tap_action:
action: call-service
service: shell_command.cancel
target: {}
name: Cancel
icon: mdi:stop
show_state: false
- show_name: true
show_icon: true
type: button
tap_action:
action: call-service
service: shell_command.pause
target: {}
name: Pause
icon: mdi:pause
- show_name: true
show_icon: true
type: button
tap_action:
action: call-service
service: shell_command.resume
target: {}
name: Resume
icon: mdi:play
Shell Command i configuration.yaml:
shell_command:
cancel: "curl -X POST -H 'Content-Type: application/json' 'http://prusalink.local/api/job' --digest -u username:password -d '{\"command\": \"cancel\"}'"
pause: "curl -X POST -H 'Content-Type: application/json' 'http://prusalink.local/api/job' --digest -u username:password -d '{\"command\": \"pause\", \"action\": [\"pause\" ]}'"
resume: "curl -X POST -H 'Content-Type: application/json' 'http://prusalink.local/api/job' --digest -u username:password -d '{\"command\": \"pause\", \"action\": [\"resume\"]}'"
Automation:
alias: Notify when 3d printer is done printing
description: ""
trigger:
- platform: state
entity_id:
- sensor.3d_printer_status
from: PRINTING
to: IDLE
condition: []
action:
- service: tts.speak
data:
cache: true
media_player_entity_id: media_player.nest_mini
message: Print is ready
language: en
target:
entity_id: tts.google_en
mode: single
My comments so far:
-
I am happy with the sensors and entity card. It looks good and work for me.
-
Values for time can handle prints more than 24 hours using timedelta. Nice!
-
Only shows values for jobs when status is printing.
-
When Pi is constantly on and printer powers off when not in use, reconnecting to PrusaLink works
-
Password for rest uses secrets.yaml. Good!
-
Password for shell_commands do NOT use secrets.yaml. This is not good.
-
RESTful Command can not handle HTTP Digest Authentication, so I’m stuck with Shell Commands for now. Seems easy to implement but someone have to do it
-
Command buttons have not ben tested fully yet. Don’t know if it’s working
-
There is a URL for a small gcode thumbnail in /api/v1/cameras/snap key file.refs.thumbnail. Have no idea how to store a picture in a variable and display on a picture card
-
There is a command for getting camera snapshot using: http://prusalink.local/api/v1/cameras/snap’ --digest -u username:password -o snapshot.png. But don’t know how to implement it.
-
All automations is not ready. To get a notification one minute before print is ready I was thinking about this: {{ as_timedelta(states(‘sensor.3d_printer_estimated_print_time’)) < timedelta(seconds=60) }} Trigger can monitor this for true
Enjoy and feel free to try out and comment.
Tomas Berglund Sweden