Skip to content

Commit

Permalink
0.0.1
Browse files Browse the repository at this point in the history
  • Loading branch information
jneilliii committed Jan 7, 2024
0 parents commit 0283ed2
Show file tree
Hide file tree
Showing 17 changed files with 1,536 additions and 0 deletions.
18 changes: 18 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# This file is for unifying the coding style for different editors and IDEs
# editorconfig.org

root = true

[*]
end_of_line = lf
charset = utf-8
insert_final_newline = true
trim_trailing_whitespace = true

[**.py]
indent_style = space
indent_size = 4

[**.js]
indent_style = space
indent_size = 4
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
*.pyc
*.swp
.idea
*.iml
build
dist
*.egg*
.DS_Store
*.zip
extras
4 changes: 4 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
include README.md
recursive-include octoprint_bambu_printer/templates *
recursive-include octoprint_bambu_printer/translations *
recursive-include octoprint_bambu_printer/static *
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# OctoPrint-BambuPrinter

**TODO:** Describe what your plugin does.

## Setup

Install via the bundled [Plugin Manager](https://docs.octoprint.org/en/master/bundledplugins/pluginmanager.html)
or manually using this URL:

https://github.com/jneilliii/OctoPrint-BambuPrinter/archive/master.zip

**TODO:** Describe how to install your plugin, if more needs to be done than just installing it via pip or through
the plugin manager.

## Configuration

**TODO:** Describe your plugin's configuration options (if any).
8 changes: 8 additions & 0 deletions babel.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[python: */**.py]

[jinja2: */**.jinja2]
silent=false
extensions=jinja2.ext.do, octoprint.util.jinja.trycatch

[javascript: */**.js]
extract_messages = gettext, ngettext
135 changes: 135 additions & 0 deletions octoprint_bambu_printer/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# coding=utf-8
from __future__ import absolute_import

import threading
import time

import octoprint.plugin

from .ftpsclient import IoTFTPSClient


class BambuPrintPlugin(
octoprint.plugin.SettingsPlugin, octoprint.plugin.TemplatePlugin
):

def get_template_configs(self):
return [{"type": "settings", "custom_bindings": False}]

def get_settings_defaults(self):
return {"device_type": "X1C",
"serial": "",
"host": "",
"access_code": "",
"username": "bblp",
"timelapse": False,
"bed_leveling": True,
"flow_cali": False,
"vibration_cali": True,
"layer_inspect": True,
"use_ams": False}

def support_3mf_files(self):
return {'machinecode': {'3mf': ["3mf"]}}

def upload_to_sd(self, printer, filename, path, sd_upload_started, sd_upload_succeeded, sd_upload_failed, *args, **kwargs):
self._logger.debug(f"Starting upload from {filename} to {filename}")
sd_upload_started(filename, filename)
def process():
host = self._settings.get(["host"])
access_code = self._settings.get(["access_code"])
elapsed = time.monotonic()

try:
ftp = IoTFTPSClient(f"{host}", 990, "bblp", f"{access_code}", ssl_implicit=True)
if ftp.upload_file(path, f"{filename}"):
elapsed = time.monotonic() - elapsed
sd_upload_succeeded(filename, filename, elapsed)
# remove local file after successful upload to Bambu
self._file_manager.remove_file("local", filename)
else:
raise Exception("upload failed")
except Exception as e:
elapsed = time.monotonic() - elapsed
sd_upload_failed(filename, filename, elapsed)
self._logger.debug(f"Error uploading file {filename}")

thread = threading.Thread(target=process)
thread.daemon = True
thread.start()

return filename

def virtual_printer_factory(self, comm_instance, port, baudrate, read_timeout):
if not port == "BAMBU":
return None

if self._settings.get(["serial"]) == "" or self._settings.get(["host"]) == "" or self._settings.get(["access_code"]) == "":
return None

import logging.handlers

from octoprint.logging.handlers import CleaningTimedRotatingFileHandler

seriallog_handler = CleaningTimedRotatingFileHandler(
self._settings.get_plugin_logfile_path(postfix="serial"),
when="D",
backupCount=3,
)
seriallog_handler.setFormatter(logging.Formatter("%(asctime)s %(message)s"))
seriallog_handler.setLevel(logging.DEBUG)

from . import virtual

serial_obj = virtual.BambuPrinter(
self._settings,
self._printer_profile_manager,
data_folder=self.get_plugin_data_folder(),
seriallog_handler=seriallog_handler,
read_timeout=float(read_timeout),
faked_baudrate=baudrate,
)
return serial_obj

def get_additional_port_names(self, *args, **kwargs):
if self._settings.get(["serial"]) != "" and self._settings.get(["host"]) != "" and self._settings.get(["access_code"]) != "":
return ["BAMBU"]
else:
return []

def get_update_information(self):
return {'bambu_printer': {'displayName': "Bambu Printer",
'displayVersion': self._plugin_version,
'type': "github_release",
'user': "jneilliii",
'repo': "OctoPrint-BambuPrinter",
'current': self._plugin_version,
'stable_branch': {'name': "Stable",
'branch': "master",
'comittish': ["master"]},
'prerelease_branches': [
{'name': "Release Candidate",
'branch': "rc",
'comittish': ["rc", "master"]}
],
'pip': "https://github.com/jneilliii/OctoPrint-BambuPrinter/archive/{target_version}.zip"}}


__plugin_name__ = "Bambu Printer"
__plugin_pythoncompat__ = ">=3.7,<4"


def __plugin_load__():
plugin = BambuPrintPlugin()

global __plugin_implementation__
__plugin_implementation__ = plugin

global __plugin_hooks__
__plugin_hooks__ = {
"octoprint.comm.transport.serial.factory": __plugin_implementation__.virtual_printer_factory,
"octoprint.comm.transport.serial.additional_port_names": __plugin_implementation__.get_additional_port_names,
"octoprint.filemanager.extension_tree": __plugin_implementation__.support_3mf_files,
"octoprint.printer.sdcardupload": __plugin_implementation__.upload_to_sd,
"octoprint.plugin.softwareupdate.check_config": __plugin_implementation__.get_update_information,
}
2 changes: 2 additions & 0 deletions octoprint_bambu_printer/ftpsclient/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from ._client import IoTFTPSClient
from ._version import __version__
159 changes: 159 additions & 0 deletions octoprint_bambu_printer/ftpsclient/_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
"""wrapper for FTPS server interactions"""

import ftplib
import ssl
from typing import List, Optional, Union


class ImplicitTLS(ftplib.FTP_TLS):
"""ftplib.FTP_TLS sub-class to support implicit SSL FTPS"""

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._sock = None

@property
def sock(self):
"""return socket"""
return self._sock

@sock.setter
def sock(self, value):
"""wrap and set SSL socket"""
if value is not None and not isinstance(value, ssl.SSLSocket):
value = self.context.wrap_socket(value)
self._sock = value

def ntransfercmd(self, cmd, rest=None):
conn, size = ftplib.FTP.ntransfercmd(self, cmd, rest)
if self._prot_p:
conn = self.context.wrap_socket(conn,
server_hostname=self.host,
session=self.sock.session) # this is the fix
return conn, size


class IoTFTPSClient:
"""iot ftps ftpsclient"""

ftps_host: str
ftps_port: int
ftps_user: str
ftps_pass: str
ssl_implicit: bool
ftps_session: Union[ftplib.FTP, ImplicitTLS]

def __init__(
self,
ftps_host: str,
ftps_port: Optional[int] = 21,
ftps_user: Optional[str] = "",
ftps_pass: Optional[str] = "",
ssl_implicit: Optional[bool] = False,
) -> None:
self.ftps_host = ftps_host
self.ftps_port = ftps_port
self.ftps_user = ftps_user
self.ftps_pass = ftps_pass
self.ssl_implicit = ssl_implicit
self.instantiate_ftps_session()

def __repr__(self) -> str:
return (
"IoT FTPS Client\n"
"--------------------\n"
f"host: {self.ftps_host}\n"
f"port: {self.ftps_port}\n"
f"user: {self.ftps_user}\n"
f"ssl: {self.ssl_implicit}"
)

def instantiate_ftps_session(self) -> None:
"""init ftps_session based on input params"""
try:
if self.ssl_implicit:
self.ftps_session = ImplicitTLS()
else:
self.ftps_session = ftplib.FTP()

self.ftps_session.connect(host=self.ftps_host, port=self.ftps_port)

if self.ftps_user != "" and self.ftps_pass != "":
self.ftps_session.login(user=self.ftps_user, passwd=self.ftps_pass)
else:
self.ftps_session.login()

if self.ssl_implicit:
self.ftps_session.prot_p()

except Exception as ex:
print(f"unexpected exception occurred: {ex}")
pass
return

def disconnect(self) -> None:
"""disconnect the current session from the ftps server"""
try:
self.ftps_session.close()
except Exception as ex:
print(f"unexpected exception occurred: {ex}")
pass
return

def download_file(self, source: str, dest: str) -> bool:
"""download a file to a path on the local filesystem"""
try:
with open(dest, "wb") as file:
self.ftps_session.retrbinary(f"RETR {source}", file.write)
return True
except Exception as ex:
print(f"unexpected exception occurred: {ex}")
pass
return False

def upload_file(self, source: str, dest: str) -> bool:
"""upload a file to a path inside the FTPS server"""
try:
with open(source, "rb") as file:
self.ftps_session.storbinary(f"STOR {dest}", file)
return True
except Exception as ex:
print(f"unexpected exception occurred: {ex}")
pass
return False

def delete_file(self, path: str) -> bool:
"""delete a file from under a path inside the FTPS server"""
try:
self.ftps_session.delete(path)
return True
except Exception as ex:
print(f"unexpected exception occurred: {ex}")
pass
return False

def move_file(self, source: str, dest: str) -> bool:
"""move a file inside the FTPS server to another path inside the FTPS server"""
try:
self.ftps_session.rename(source, dest)
return True
except Exception as ex:
print(f"unexpected exception occurred: {ex}")
pass
return False

def list_files(
self, path: str, file_pattern: Optional[str] = None
) -> Union[List[str], None]:
"""list files under a path inside the FTPS server"""
try:
files = self.ftps_session.nlst(path)
if not files:
return
if file_pattern:
return [f for f in files if file_pattern in f]
return files
except Exception as ex:
print(f"unexpected exception occurred: {ex}")
pass
return
3 changes: 3 additions & 0 deletions octoprint_bambu_printer/ftpsclient/_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
VERSION = "1.1.1"

__version__ = VERSION
29 changes: 29 additions & 0 deletions octoprint_bambu_printer/static/js/bambu_printer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* View model for OctoPrint-BambuPrinter
*
* Author: jneilliii
* License: AGPLv3
*/
$(function() {
function Bambu_printerViewModel(parameters) {
var self = this;

// assign the injected parameters, e.g.:
// self.loginStateViewModel = parameters[0];
// self.settingsViewModel = parameters[1];

// TODO: Implement your plugin's view model here.
}

/* view model class, parameters for constructor, container to bind to
* Please see http://docs.octoprint.org/en/master/plugins/viewmodels.html#registering-custom-viewmodels for more details
* and a full list of the available options.
*/
OCTOPRINT_VIEWMODELS.push({
construct: Bambu_printerViewModel,
// ViewModels your plugin depends on, e.g. loginStateViewModel, settingsViewModel, ...
dependencies: [ /* "loginStateViewModel", "settingsViewModel" */ ],
// Elements to bind to, e.g. #settings_plugin_bambu_printer, #tab_plugin_bambu_printer, ...
elements: [ /* ... */ ]
});
});
Loading

0 comments on commit 0283ed2

Please sign in to comment.