Skip to content

Commit

Permalink
Merge pull request #4 from d3vyce/main
Browse files Browse the repository at this point in the history
add octoprint and prusa support + refactor Printer Type
  • Loading branch information
sphawes authored Oct 2, 2024
2 parents 73c363a + 4ca50f5 commit a2bd464
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 61 deletions.
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,41 @@ Click on "Choose Folder to Upload" to select a folder where all your pre-sliced

Hit "Send to Farm" to upload all files in the folder to your print farm. The log will notify you of success or failure.

## Compatible Printer
### Bambu Lab
```json
{
"name": "XXXXX",
"type": "Bambu",
"ip": "XXX.XXX.XXX.XXX",
"user": "bblp",
"pw": "12345678"
}
```

### Octoprint
```json
{
"name": "XXXXX",
"type": "Octoprint",
"ip": "XXX.XXX.XXX.XXX",
"port": "80",
"api_key": "XXXXXXXXXXXXXX",
"location": "local/sdcard"
}
```

### Prusa (Mini, MK4, XL)
```json
{
"name": "XXXXX",
"type": "Prusa",
"ip": "XXX.XXX.XXX.XXX",
"port": "80",
"api_key": "XXXXXXXXXXXXXX"
}
```

## Todo

- Test on printers other than BambuLab P1P
Expand Down
21 changes: 20 additions & 1 deletion settings-example.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,32 @@
"printers": [
{
"name": "Printer #1",
"type": "Bambu",
"ip": "192.168.1.1",
"user": "bblp",
"pw": "12345678"
},
{
"name": "Printer #2",
"type": "Bambu",
"ip": "192.168.1.2",
"user": "bblp",
"pw": "12345678"
},
{
"name": "Printer #3",
"type": "Octoprint",
"ip": "192.168.1.3",
"port": "80",
"api_key": "XXXXXXXXXXXXXX",
"location": "local"
},
{
"name": "Printer #4",
"type": "Prusa",
"ip": "192.168.1.4",
"port": "80",
"api_key": "XXXXXXXXXXXXXX"
}
]
}
}
6 changes: 4 additions & 2 deletions src/BambuFTP.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@
"""

import ftplib
import ssl, os
import ssl

class Error(Exception): pass
CRLF = '\r\n'
B_CRLF = b'\r\n'

_SSLSocket = ssl.SSLSocket

class Error(Exception):
pass

# ftps = FTP('192.168.1.204', 990)
# ftps.debugging = 2
# #ftps.connect('192.168.1.212', 990)
Expand Down
48 changes: 22 additions & 26 deletions src/FarmUpload.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import tkinter as tk
from tkinter import filedialog
import tkinter.scrolledtext as st
import json, os
import threading, queue
import json
import os
import threading
import queue

from Printer import Printer
import PrinterType
from Log import Logger

class App():
Expand Down Expand Up @@ -33,16 +35,18 @@ def loadSettings(self):

# loading printers into app printer array

for printer in self.settings["printers"]:
var = tk.BooleanVar()
self.printers.append(Printer(
name = printer["name"],
ip = printer["ip"],
pw = printer["pw"],
enabled = var
))
for printer_conf in self.settings["printers"]:
enabled = tk.BooleanVar()
printer_conf["enabled"] = enabled

checkbox = tk.Checkbutton(self.printerSelectFrame, text=printer["name"], variable=var, onvalue=True, offvalue=False)
try:
PrinterClass = getattr(PrinterType, printer_conf.get("type"))
except AttributeError:
self.log.write("Printer type unknown: " + printer_conf.get("type"))
continue

self.printers.append(PrinterClass(printer_conf))
checkbox = tk.Checkbutton(self.printerSelectFrame, text=printer_conf.get("name"), variable=enabled, onvalue=True, offvalue=False)
checkbox.pack(side=tk.LEFT, pady=10)

self.s.update_idletasks()
Expand Down Expand Up @@ -101,22 +105,14 @@ def sendOnePrinter(self, printer, toSend):
self.logQueue.put("Connected to " + str(printer.name))

for filename in toSend:
try:
with open(os.path.join(self.fileDirectory,filename), 'rb') as file:
self.logQueue.put("Sending " + str(filename) + " to printer " + printer.name + "..." )

printer.ftp.storbinary(f'STOR {filename}', file)
self.logQueue.put("Success: " + str(filename) + " to printer " + printer.name)
with open(os.path.join(self.fileDirectory,filename), 'rb') as file:
self.logQueue.put("Sending " + str(filename) + " to printer " + printer.name + "..." )

except:
try:
with open(os.path.join(self.fileDirectory,filename), 'rb') as file:
self.logQueue.put("Reattempting to send " + str(filename) + " to printer " + printer["name"] + "..." )
printer.ftp.storbinary(f'STOR {filename}', file)
self.logQueue.put("Success: " + str(filename) + " to printer " + printer.name)
except:
return_status = printer.send(filename, file, self.logQueue)
if return_status:
self.logQueue.put("Success: " + str(filename) + " to printer " + printer.name)
else:
self.logQueue.put("Failure: " + str(filename) + " to printer " + printer.name)

printer.disconnect()

else:
Expand Down
1 change: 0 additions & 1 deletion src/Log.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import tkinter as tk
import logging

class Logger():
"""This class allows you to log to a Tkinter Text or ScrolledText widget"""
Expand Down
31 changes: 0 additions & 31 deletions src/Printer.py

This file was deleted.

135 changes: 135 additions & 0 deletions src/PrinterType.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import ftplib
import io
import requests
import time
import queue
from BambuFTP import BambuFTP

MAX_SEND_RETRY = 5


class Printer:
def __init__(self, config: dict) -> None:
self.name = config.get("name")
self.type = config.get("type")
self.ip = config.get("ip")
self.enabled = config.get("enabled")
self.connected = False


class Bambu(Printer):
def __init__(self, config: dict) -> None:
Printer.__init__(self, config)

self.user = config.get("user")
self.pw = config.get("pw")
self.ftp = BambuFTP()

self.ftp.set_pasv(True)

def connect(self) -> None:
try:
self.ftp.connect(host=self.ip, port=990, timeout=10, source_address=None)
self.ftp.login(self.user, self.pw)
self.ftp.prot_p()
self.connected = True
except ftplib.all_errors:
return False

def send(self, filename: str, file: io.BytesIO, logger: queue.Queue) -> bool:
for i in range(1, MAX_SEND_RETRY+1):
try:
self.ftp.storbinary(f"STOR {filename}", file)
except ftplib.all_errors:
logger.put(f"Error: reattempting to send to {self.name} ({i}/{MAX_SEND_RETRY})")
time.sleep(1)
continue
return True
return False

def disconnect(self) -> None:
try:
self.ftp.quit()
self.connected = False
except ftplib.all_errors:
return False


class Octoprint(Printer):
def __init__(self, config: dict) -> None:
Printer.__init__(self, config)

self.port = config.get("port")
self.api_key = config.get("api_key")
self.location = config.get("location")

def connect(self) -> None:
headers = {"X-Api-Key": self.api_key}
response = requests.get(
f"http://{self.ip}:{self.port}/api/version",
headers=headers,
)
if response.status_code == 200:
self.connected = True
return
self.connected = False

def send(self, filename: str, file: io.BytesIO, logger: queue.Queue) -> bool:
headers = {"X-Api-Key": self.api_key}
for i in range(1, MAX_SEND_RETRY+1):
try:
response = requests.post(
f"http://{self.ip}:{self.port}/api/files/{self.location}",
files={"file": file, "filename": filename},
headers=headers,
)
if response.status_code == 201:
return True
except BaseException as exception:
logger.put(f"{type(exception).__name__}: reattempting to send to {self.name} ({i}/{MAX_SEND_RETRY})")
time.sleep(1)
return False

def disconnect(self) -> None:
self.connected = False


class Prusa(Printer):
def __init__(self, config: dict) -> None:
Printer.__init__(self, config)

self.port = config.get("port")
self.api_key = config.get("api_key")

def connect(self) -> None:
headers = {"X-Api-Key": self.api_key}
response = requests.get(
f"http://{self.ip}:{self.port}/api/version",
headers=headers,
)
if response.status_code == 200:
self.connected = True
return
self.connected = False

def send(self, filename: str, file: io.BytesIO, logger: queue.Queue) -> bool:
headers={
"X-Api-Key": self.api_key,
"Overwrite": "?1",
}
for i in range(1, MAX_SEND_RETRY+1):
try:
response = requests.put(
f"http://{self.ip}:{self.port}/api/v1/files/usb/{filename}",
data=file,
headers=headers,
)
if response.status_code == 201:
return True
except BaseException as exception:
logger.put(f"{type(exception).__name__}: reattempting to send to {self.name} ({i}/{MAX_SEND_RETRY})")
time.sleep(1)
return False

def disconnect(self) -> bool:
self.connected = False

0 comments on commit a2bd464

Please sign in to comment.