PrusaLinkPy is a library to use the Prusa Link API.
The library makes it easy to use the prusa API in python. The library is based on Request.
Installation, update :
pip install prusaLinkPy
pip install prusaLinkPy -U
Example of use :
# Library import
import PrusaLinkPy
# Printer instantiation
# IP : 192.168.0.123
# API KEY : 8ojHKHGNuAHA2bM
prusaMini = PrusaLinkPy.PrusaLinkPy("192.168.0.123", "8ojHKHGNuAHA2bM")
# Get bed temperature
getPrint = prusaMini.get_printer()
# Display bed temperature
print(getPrint.json()["telemetry"]["temp-bed"])
# Delete a files on USB drive :
prusaMini.delete("/5H30M_~1.GCO")
# Transferring a file to the printer
if not prusaMini.exists_gcode('FOLDER/test.gcode') :
prusaMini.put_gcode('C:/AM/test.gcode', 'FOLDER/test.gcode')
# List files on USB Drive :
prusaMini.get_files().json()["children"]
# Print this file
prusaMini.post_print_gcode('/usb/test.gcode')
The library changed its name in May 2024. Before it was called prusaLink. Prusa staff asked me to leave them the name.
Tab correction
Version made by enrgarci
PrusaLinkPy is available on pip :
python -m pip install PrusaLinkPy
PrusaLinkPy officially supports Python 3.9+ with Prusa printers (MINI, MK4 or XL) firmware 5.1.0.
put_gcode(filePathLocal, remoteDir, printAfterUpload = False, overwrite = False)
Not documented :
For compatibility with old versions :
get_recursive_files(remoteDir)
Read version :
import PrusaLinkPy
prusaMini = PrusaLinkPy.PrusaLinkPy("192.168.0.123", "8ojHKHGNuAHA2bM", port=8017)
obj = prusaMini.get_version()
obj.json()
Return something like :
{
'api': '2.0.0',
'server': '2.1.2',
'nozzle_diameter': 0.4,
'text': 'PrusaLink',
'hostname': '',
'capabilities':
{
'upload-by-put': True
}
}
Get printer :
import PrusaLinkPy
prusaMini = PrusaLinkPy.PrusaLinkPy("192.168.0.123", "8ojHKHGNuAHA2bM")
obj = prusaMini.get_printer()
obj.json()
Waiting for Changing Filament :
'link_state': 'ATTENTION'
'error': True
Return something like :
{
'telemetry':
{
'temp-bed': 16.3,
'temp-nozzle': 16.7,
'print-speed': 100,
'z-height': 82.0,
'material': 'PLA'
},
'temperature':
{
'tool0':
{
'actual': 16.7,
'target': 0.0,
'display': 0.0,
'offset': 0
},
'bed':
{
'actual':16.3,
'target': 0.0,
'offset': 0
}
},
'state':
{
'text': 'Operational',
'flags':
{
'operational': True,
'paused': False,
'printing': False,
'cancelling': False,
'pausing': False,
'error': False,
'sdReady': False,
'closedOnError': False,
'ready': True,
'busy': False
}
}
}
Get job :
import PrusaLinkPy
prusaMini = PrusaLinkPy.PrusaLinkPy("192.168.0.123", "8ojHKHGNuAHA2bM")
obj = prusaMini.get_job()
obj.json()
Return something like :
{
"state":"Operational",
"job": None,
"progress": None
}
Delete a job. Job number is available with get_job() or get_status()
import PrusaLinkPy
prusaMini = PrusaLinkPy.PrusaLinkPy("192.168.0.123", "8ojHKHGNuAHA2bM")
obj = prusaMini.delete_job("43")
Get job :
import PrusaLinkPy
prusaMini = PrusaLinkPy.PrusaLinkPy("192.168.0.123", "8ojHKHGNuAHA2bM")
obj = prusaMini.get_status()
obj.json()
Value of printer->state :
IDLE (Main Screen)
PRINTING
FINISHED (Print finish, screen not on main screen)
PAUSED (Pause by user, Print fan error)
STOPPED (Print finish, stopped by user)
ATTENTION (Filament Change)
Return something like :
{
"job":
{
"id":43,
"progress":0.00,
"time_remaining":120,
"time_printing":143
},
"storage":
{
"path":"/usb/",
"name":"usb",
"read_only":false
},
"printer":
{
"state":"PRINTING",
"temp_bed":57.3,
"target_bed":0.0,
"temp_nozzle":24.1,
"target_nozzle":0.0,
"axis_z":162.2,
"flow":100,
"speed":100,
"fan_hotend":0,
"fan_print":0
}
}
Get job :
import PrusaLinkPy
prusaMini = PrusaLinkPy.PrusaLinkPy("192.168.0.123", "8ojHKHGNuAHA2bM")
obj = prusaMini.get_storage()
obj.json()
Return something like :
{
'storage_list':
[
{
'path': '/usb/',
'name': 'usb',
'type': 'USB',
'read_only': False,
'available': True
}
]
}
Not Tested
Get job :
import PrusaLinkPy
prusaMini = PrusaLinkPy.PrusaLinkPy("192.168.0.123", "8ojHKHGNuAHA2bM")
obj = prusaMini.get_transfer()
obj.text
Return something like :
TODO
Completely useless
See here :
Comment from Prusa Developper :
// Some stubs for now, to make more clients (including the web page) happier.
Get job :
import PrusaLinkPy
prusaMini = PrusaLinkPy.PrusaLinkPy("192.168.0.123", "8ojHKHGNuAHA2bM")
obj = prusaMini.get_transfer()
obj.text
Return something like :
{"printer": {}}
Get Files on USB Drive :
import PrusaLinkPy
prusaMini = PrusaLinkPy.PrusaLinkPy("192.168.0.123", "8ojHKHGNuAHA2bM")
obj = prusaMini.get_files()
filesRet = obj.json()
Return something like :
{
'type': 'FOLDER',
'ro': False,
'name': 'usb',
'children':
[
{
'name': 'MTN',
'ro': False,
'type': 'FOLDER',
'm_timestamp': 1702628945,
'display_name': 'MTN'
},
{
'name': 'S2_V2IS',
'ro': False,
'type': 'FOLDER',
'm_timestamp': 1702565182,
'display_name': 'S2_V2IS'
}
]
}
Workalso with subfolder
obj = prusaMini.get_files(remoteDir = '/SUBFOLDER')
Get all files (only gcode and bgcode) in a folder and subfolder.
Warning : return nested dict.
import PrusaLinkPy
prusaMini = PrusaLinkPy.PrusaLinkPy("192.168.0.123", "8ojHKHGNuAHA2bM")
dictt = prusaMini.get_recursive_files()
{
'MTN':
{
'CHGT_BUSE.gcode': '/MTN/CHGT_B~1.GCO',
'DEBOUCHAGE.gcode': '/MTN/DEBOUC~1.GCO',
'PRECHAUFFE.gcode': '/MTN/PRECHA~1.GCO'
},
'S2_V2IS':
{
'2h33m.bgcode': '/S2_V2IS/2H33M~1.BGC',
'5h5m.bgcode': '/S2_V2IS/5H5M~1.BGC'
}
}
Delete a file or a folder on USB drive
import PrusaLinkPy
prusaMini = PrusaLinkPy.PrusaLinkPy("192.168.0.123", "8ojHKHGNuAHA2bM")
obj = prusaMini.delete('/DEBOUC~1.GCO')
Print a file already poresent on USB key
import PrusaLinkPy
prusaMini = PrusaLinkPy.PrusaLinkPy("192.168.0.123", "8ojHKHGNuAHA2bM")
obj = prusaMini.post_gcode('/DEBOUC~1.GCO')
Send a file on USB Drive.
Can create a folder !
if ret.status_code = 409 -> Conflict : File already exists if ret.status_code = 415 -> {"title": "415: Unsupported Media Type","message":"Not a GCODE"}
printAfterUpload : Set at True to print after upload.
overwrite : Allow file Overwrite
FW 5.1.0 :
Can only send bgcode and gcode
import PrusaLinkPy prusaMini = PrusaLinkPy.PrusaLinkPy("192.168.0.123", "8ojHKHGNuAHA2bM") status = prusaMini.put('C:/MTN/DEBOUCHAGE.gcode' , 'MTN/DEBOUCHAGE.gcode')
status = prusaMini.put('C:/MTN/DEBOUCHAGE.gcode' , 'MTN/DEBOUCHAGE.gcode', False, True)
status = prusaMini.put('C:/MTN/DEBOUCHAGE.gcode' , 'MTN/DEBOUCHAGE.gcode', True, True)
Check if a file exists on USB drive.
Return True or False
import PrusaLinkPy
prusaMini = PrusaLinkPy.PrusaLinkPy("192.168.0.123", "8ojHKHGNuAHA2bM")
status = prusaMini.exists_gcode('/DEBOUC~1.GCO')
Pause actual print.
Added in 2.2.0 .
Resume paused print.
Added in 2.2.0 .
Stop actual print.
Added in 2.2.0 .
API not implemented in my lib :
retrieve thumbnail :
r = requests.get('http://192.168.0.123:8017/thumb/l/usb/TAVERN~1.GCO', headers=headers)
/api/settings
POST /api/job Link to Buddy code
GET/POST /api/download Link to Buddy code
There is no possibility to have the list of folders present in a directory
You cannot upload a gcode in a subfolder of the USB key
When the printer detects the end of the filament and it displays "Change Filament" the telemetry information is no longer good. Here is the information returned by the printer in this case:
'telemetry': {'temp-bed': 0.0, 'temp-nozzle': 0.0, 'print-speed': 100, 'z-height': 0.0, 'material': '---'}
Still in the case of a filament change, the status information is incorrect:
'state': {'text': 'Operational', 'flags': {'operational': True, 'paused': False, 'printing': False, 'cancelling': False, 'pausing': False, 'sdReady': False, 'error': False, 'closedOnError': False, 'ready': True, 'busy': False}
An other lib :
https://github.com/home-assistant-libs/PrusaLinkPy/blob/main/PrusaLinkPy/
Les commandes dans la mini : https://github.com/prusa3d/Prusa-Firmware-Buddy/blob/master/lib/WUI/link_content/basic_gets.cpp
py -m build
To upload to testpi repo :
py -m twine upload --repository testpi dist/*
To upload to pypi repo :
py -m twine upload dist/*
https://medium.com/analytics-vidhya/how-to-create-a-python-library-7d5aea80cc3f