Get Prusa 3D Printer Status with Python (rev.1)¶
Still Unstable... need to revise more This notebook is a update version from the first version of printer-serial.ipynb
Warning
This notebook should run in your local PC, not fabcloud Jupyter server
Reference:
We can get current printer status with sending G-Code via serial communication, as show in Previous version.
For example:
- M105 : Could get Temperture status of the printer
- M114 : Could get X,Y,Z position and extrusion amount or position of the extruder
Moreover, I found the following command.
- M155 : Count output Temperature, fan status and position automatically
But, connecting to my Prusa Core One and try to send this command, only temperature data could output. Searching the documents of Prusa firmware and other website, at present, I cannot get printer position data automatically.
Therefore, whereas getting temperature data automatically, we need to continueing poll "M114" command continuously.
So, I asked Chat GPT as following to revise previous version:
Please revise previous version of code to get temperture and positon data from Prusa To get temperature data, use M155 command, and use M114 command to get position data.
Then he replied the folliwng code.
First, import serial library and time library
import serial
import threading
import time
from datetime import datetime
import serial.tools.list_ports as list_ports
Then, check the serial port path
ports = list_ports.comports()
for port,desc,hwid in sorted(ports):
print(f"{port}: {desc} [{hwid}]")
/dev/cu.AnkerPowerConf: n/a [n/a] /dev/cu.Bluetooth-Incoming-Port: n/a [n/a] /dev/cu.debug-console: n/a [n/a] /dev/cu.usbmodem2101: Original Prusa COREONE [USB VID:PID=2C99:001F SER=13052-4742441644809810 LOCATION=2-1]
Set Configurations
PORT = "/dev/cu.usbmodem2101"
BAUD = 115200
TEMP_LOG_FILE = "./printer_data_temp_infill.txt"
POS_LOG_FILE = "./printer_data_position_infill.txt"
PRINT_DEBUG = True
stop_event = threading.Event()
This is the function to save the data from the printer.
def log_line(filepath: str, line: str) -> None:
"""タイムスタンプ付きで1行ログファイルに書き込む"""
ts = datetime.now().strftime("%Y/%m/%d-%H:%M:%S.%f")
with open(filepath, "a", encoding="utf-8") as f:
f.write(f"{ts} {line}\n")
Here is the code that parse logdata and detect the temperature data or position data. Only catching up temperature and position. Other data (like error message, status message from the printer) are dropped here.
(I dropped those status data, but maybe it could be used for analyzing.... )
def classify_and_log(line: str) -> None:
# busy
if "busy: processing" in line:
if PRINT_DEBUG:
print("BUSY:", line)
return
# echo メッセージ
if line.startswith("echo:"):
if PRINT_DEBUG:
print("ECHO:", line)
return
# 温度行(M155のオートレポート + M105 の応答など)
if "T:" in line and "B:" in line:
# 念のため 'ok ' が頭についていたら削除
data = line.lstrip("ok ").strip()
log_line(TEMP_LOG_FILE, data)
if PRINT_DEBUG:
print("TEMP:", data)
return
# 位置行(M114の応答)
if "X:" in line and "Y:" in line and "Z:" in line and "Count" in line:
data = line.lstrip("ok ").strip()
log_line(POS_LOG_FILE, data)
if PRINT_DEBUG:
print("POS:", data)
return
# その他
if PRINT_DEBUG:
print("OTHER:", line)
This function is to keep reading serial data to get temperatura data coming automatically.
def reader_loop(ser: serial.Serial) -> None:
while not stop_event.is_set():
try:
raw = ser.readline()
except Exception as e:
print("Serial read error:", e)
break
if not raw:
continue
line = raw.decode("utf-8", errors="ignore").strip()
if not line:
continue
classify_and_log(line)
This function is to keep writing "M114" command to get position data.
def writer_loop(ser: serial.Serial) -> None:
while not stop_event.is_set():
try:
ser.write(b"M114\n")
ser.flush()
except Exception as e:
print("Serial write error:", e)
break
time.sleep(1.0)
Here is main function.
The most important point to use "threding.Thread" to get temperature data with asynchronous processing.
print(f"Opening serial port {PORT} @ {BAUD}...")
ser = serial.Serial(PORT, BAUD, timeout=1)
time.sleep(2.0)
ser.reset_input_buffer()
print("Enable temperature autoreport: M155 S1")
ser.write(b"M155 S1\n")
ser.flush()
t_reader = threading.Thread(target=reader_loop, args=(ser,), daemon=True)
t_reader.start()
try:
writer_loop(ser)
except KeyboardInterrupt:
print("Ctrl+C detected, stopping...")
finally:
stop_event.set()
time.sleep(0.5)
try:
print("Disable temperature autoreport: M155 S0")
ser.write(b"M155 S0\n")
ser.flush()
time.sleep(0.2)
except Exception as e:
print("Error while disabling M155:", e)
ser.close()
print("Serial closed.")