Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No way to move the printhead #514

Open
NovodoOfficial opened this issue Nov 30, 2024 · 0 comments
Open

No way to move the printhead #514

NovodoOfficial opened this issue Nov 30, 2024 · 0 comments

Comments

@NovodoOfficial
Copy link

The legacy API provided ways to move the printhead in the openapi legacy file but not in the current openapi file.

I have a Prusa Mini+ and am attempting to send API requests through python to move the printhead but, sending a request to the legacy API endpoint (with correct and tested Digest authentication) results in a 404 error. I know it is possible to do this as I can via the Prusa connect control screen:

image

This is a half-working implementation that I made in python:

from requests.auth import HTTPDigestAuth
import requests
import time
import os

class DebugError(Exception):
    pass

class Printer:
    def __init__(self, printer_ip, password, username="maker", debug=False):
        self.printer_ip = printer_ip
        self.username = username
        self.password = password
        self.debug = debug

        self.auth = HTTPDigestAuth(self.username, self.password)

    def send_gcode(self, gcode):
        gcode_path = "temp_prusa_api_file_gcode_command.gcode"

        with open(gcode_path, 'w') as file:
            file.write(gcode)

        self.upload_gcode(gcode_path)

    def upload_gcode(self, gcode_path, auto_start=True, overwrite=True, output=False):
        file_name = os.path.basename(gcode_path)

        upload_url = f"{self.printer_ip}/api/v1/files/usb//{file_name}"

        if self.debug:
            with open(gcode_path, 'r') as file:
                print(f"GCODE:\n{file.read()}")
            return

        headers = {
            "Origin": self.printer_ip,
            "Content-Type": "text/x.gcode",
            "Accept": "application/json",
            "Accept-Encoding": "gzip, deflate",
            "Accept-Language": "en-US,en;q=0.5",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:132.0) Gecko/20100101 Firefox/132.0"
        }

        if overwrite:
            headers["Overwrite"] = "?1"
        else:
            headers["Overwrite"] = "?0"

        if auto_start:
            headers["Print-After-Upload"] = "?1"
        else:
            headers["Print-After-Upload"] = "?0"

        status_printed = False

        while True:
            status = self.get_status()["printer"]["state"]
            if status.upper().strip() in ["FINISHED", "IDLE", "STOPPED"]:
                break
            elif not status_printed:
                status_printed = True
                print("Waiting for printer to be free")
            time.sleep(3)

        with open(gcode_path, 'rb') as file:
            response = requests.put(upload_url, data=file, headers=headers, auth=self.auth)

        if response.status_code == 201:
            if output:
                print(f"File {file_name} uploaded successfully to: {self.printer_ip}")
        else:
            raise DebugError(f"Failed to upload the file. Status code:\n{response.status_code}\n\nResponse:\n{response.text}")
        
    def get_status(self):
        if self.debug:
            return {'storage': {'path': '/usb/', 'name': 'usb', 'read_only': False}, 'printer': {'state': 'IDLE', 'temp_bed': 21.8, 'target_bed': 0.0, 'temp_nozzle': 22.2, 'target_nozzle': 0.0, 'axis_z': 105.6, 'axis_x': 170.0, 'axis_y': 170.0, 'flow': 100, 'speed': 100, 'fan_hotend': 0, 'fan_print': 0}}

        status_url = f"{self.printer_ip}/api/v1/status"
        status_response = requests.get(status_url, auth=self.auth)

        if status_response.status_code != 200:
            raise DebugError(f"Failed to fetch printer status. Status code:\n{status_response.status_code}\n\nResponse:\n{status_response.text}")
        
        return status_response.json()

class Move:
    def __init__(self):
        self.move = [None, None, None, None]

    def clear(self):
        self.move = [None, None, None, None]

    def x(self, location):
        self.move[0] = location

    def y(self, location):
        self.move[1] = location

    def z(self, location):
        self.move[2] = location
    
    def feed(self, feedrate):
        self.move[3] = feedrate

    def xy(self, locationX, locationY):
        self.move[0] = locationX
        self.move[1] = locationY

class GcodeList:
    def __init__(self):
        self.gcode_list = []
        self.lastX, self.lastY, self.lastZ = 0, 0, 0

    def clear(self):
        self.gcode_list = []

    def parse(self):
        gcode = "\n".join(self.gcode_list)

        return gcode

    def AddMove(self, move):
        if isinstance(move, list):
            if len(move) != 4:
                raise DebugError(f"Move is not a 4-length tuple:\n{move}")
            
            if move[0] == None and move[1] == None and move[2] == None and move[3] == None:
                return
            
            x = move[0]
            y = move[1]
            z = move[2]

            feed = move[3]

            x_gcode = f" X{x}"
            y_gcode = f" Y{y}"
            z_gcode = f" Z{z}"

            feed_gcode = f" F{feed}"

            if x == None:
                x_gcode = ""
            else:
                self.lastX = x
            if y == None:
                y_gcode = ""
            else:
                self.lastY = y
            if z == None:
                z_gcode = ""
            else:
                self.lastZ = z
                
            if feed == None:
                feed_gcode = ""

            gcode = f"G1{x_gcode}{y_gcode}{z_gcode}{feed_gcode}"

            self.gcode_list.append(gcode)

        if isinstance(move, str):
            if move == "home":
                self.gcode_list.append("G28")
            elif move == "absmode":
                self.gcode_list.append("G90")
            else:
                self.gcode_list.append(move)

    def AddPause(self, time_message=""):
        if isinstance(time_message, int):
            self.gcode_list.append(f"G4 {time_message}")
        elif isinstance(time_message, str):
            if time_message:
                self.gcode_list.append(f"M0 {time_message}")
            else:
                self.gcode_list.append(f"M0")

    def Message(self, message=""):
        if message:
            self.gcode_list.append(f"M117 {message}")
        else:
            self.gcode_list.append(f"M117")

This approach works but once the gcode file has finished "printing", it will park the print head which is less than ideal. Any help with this issue or support about an API endpoint would be greatly appreciated!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant