WIP: OctoPrint
This commit is contained in:
parent
79ee7c9a36
commit
7cfc5204c8
@ -410,6 +410,14 @@ sub _init_menubar {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
my $hokusMenu = Wx::Menu->new; # XXX: tmp
|
||||||
|
{
|
||||||
|
$self->_append_menu_item($hokusMenu, "Pokus", "Pokus", sub {
|
||||||
|
# Slic3r::Http::download();
|
||||||
|
Slic3r::OctoPrint::send_gcode("10.0.0.46", "70E4CFD0E0D7423CB6B1CF055DBAEFA5", "/home/vojta/prog/tisk/jesterka/jesterka.gcode");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
# menubar
|
# menubar
|
||||||
# assign menubar to frame after appending items, otherwise special items
|
# assign menubar to frame after appending items, otherwise special items
|
||||||
# will not be handled correctly
|
# will not be handled correctly
|
||||||
@ -424,6 +432,8 @@ sub _init_menubar {
|
|||||||
# (Select application language from the list of installed languages)
|
# (Select application language from the list of installed languages)
|
||||||
Slic3r::GUI::add_debug_menu($menubar, $self->{lang_ch_event});
|
Slic3r::GUI::add_debug_menu($menubar, $self->{lang_ch_event});
|
||||||
$menubar->Append($helpMenu, L("&Help"));
|
$menubar->Append($helpMenu, L("&Help"));
|
||||||
|
$menubar->Append($hokusMenu, "Hoku&s");
|
||||||
|
# Add an optional debug menu. In production code, the add_debug_menu() call should do nothing.
|
||||||
$self->SetMenuBar($menubar);
|
$self->SetMenuBar($menubar);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ sub new {
|
|||||||
my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
|
my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
|
||||||
$self->{config} = Slic3r::Config::new_from_defaults_keys([qw(
|
$self->{config} = Slic3r::Config::new_from_defaults_keys([qw(
|
||||||
bed_shape complete_objects extruder_clearance_radius skirts skirt_distance brim_width variable_layer_height
|
bed_shape complete_objects extruder_clearance_radius skirts skirt_distance brim_width variable_layer_height
|
||||||
serial_port serial_speed octoprint_host octoprint_apikey
|
serial_port serial_speed octoprint_host octoprint_apikey octoprint_cafile
|
||||||
nozzle_diameter single_extruder_multi_material
|
nozzle_diameter single_extruder_multi_material
|
||||||
wipe_tower wipe_tower_x wipe_tower_y wipe_tower_width wipe_tower_per_color_wipe extruder_colour filament_colour
|
wipe_tower wipe_tower_x wipe_tower_y wipe_tower_width wipe_tower_per_color_wipe extruder_colour filament_colour
|
||||||
)]);
|
)]);
|
||||||
@ -1458,8 +1458,13 @@ sub on_export_completed {
|
|||||||
wxTheApp->notify($message);
|
wxTheApp->notify($message);
|
||||||
|
|
||||||
$self->do_print if $do_print;
|
$self->do_print if $do_print;
|
||||||
|
|
||||||
# Send $self->{send_gcode_file} to OctoPrint.
|
# Send $self->{send_gcode_file} to OctoPrint.
|
||||||
$self->send_gcode if $send_gcode;
|
if ($send_gcode) {
|
||||||
|
my $op = Slic3r::OctoPrint->new($self->{config});
|
||||||
|
$op->send_gcode($self->GetId(), $PROGRESS_BAR_EVENT, $ERROR_EVENT, $self->{send_gcode_file});
|
||||||
|
}
|
||||||
|
|
||||||
$self->{print_file} = undef;
|
$self->{print_file} = undef;
|
||||||
$self->{send_gcode_file} = undef;
|
$self->{send_gcode_file} = undef;
|
||||||
$self->{"print_info_cost"}->SetLabel(sprintf("%.2f" , $self->{print}->total_cost));
|
$self->{"print_info_cost"}->SetLabel(sprintf("%.2f" , $self->{print}->total_cost));
|
||||||
@ -1488,45 +1493,6 @@ sub do_print {
|
|||||||
my $filament_names = wxTheApp->{preset_bundle}->filament_presets;
|
my $filament_names = wxTheApp->{preset_bundle}->filament_presets;
|
||||||
$filament_stats = { map { $filament_names->[$_] => $filament_stats->{$_} } keys %$filament_stats };
|
$filament_stats = { map { $filament_names->[$_] => $filament_stats->{$_} } keys %$filament_stats };
|
||||||
$printer_panel->load_print_job($self->{print_file}, $filament_stats);
|
$printer_panel->load_print_job($self->{print_file}, $filament_stats);
|
||||||
|
|
||||||
$self->GetFrame->select_tab(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
# Send $self->{send_gcode_file} to OctoPrint.
|
|
||||||
#FIXME Currently this call blocks the UI. Make it asynchronous.
|
|
||||||
sub send_gcode {
|
|
||||||
my ($self) = @_;
|
|
||||||
|
|
||||||
$self->statusbar->StartBusy;
|
|
||||||
|
|
||||||
my $ua = LWP::UserAgent->new;
|
|
||||||
$ua->timeout(180);
|
|
||||||
|
|
||||||
my $res = $ua->post(
|
|
||||||
"http://" . $self->{config}->octoprint_host . "/api/files/local",
|
|
||||||
Content_Type => 'form-data',
|
|
||||||
'X-Api-Key' => $self->{config}->octoprint_apikey,
|
|
||||||
Content => [
|
|
||||||
file => [
|
|
||||||
# On Windows, the path has to be encoded in local code page for perl to be able to open it.
|
|
||||||
Slic3r::encode_path($self->{send_gcode_file}),
|
|
||||||
# Remove the UTF-8 flag from the perl string, so the LWP::UserAgent can insert
|
|
||||||
# the UTF-8 encoded string into the request as a byte stream.
|
|
||||||
Slic3r::path_to_filename_raw($self->{send_gcode_file})
|
|
||||||
],
|
|
||||||
print => $self->{send_gcode_file_print} ? 1 : 0,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
$self->statusbar->StopBusy;
|
|
||||||
|
|
||||||
if ($res->is_success) {
|
|
||||||
$self->statusbar->SetStatusText(L("G-code file successfully uploaded to the OctoPrint server"));
|
|
||||||
} else {
|
|
||||||
my $message = L("Error while uploading to the OctoPrint server: ") . $res->status_line;
|
|
||||||
Slic3r::GUI::show_error($self, $message);
|
|
||||||
$self->statusbar->SetStatusText($message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub export_stl {
|
sub export_stl {
|
||||||
|
@ -201,6 +201,8 @@ add_library(libslic3r_gui STATIC
|
|||||||
${LIBDIR}/slic3r/GUI/wxExtensions.hpp
|
${LIBDIR}/slic3r/GUI/wxExtensions.hpp
|
||||||
${LIBDIR}/slic3r/Utils/Http.cpp
|
${LIBDIR}/slic3r/Utils/Http.cpp
|
||||||
${LIBDIR}/slic3r/Utils/Http.hpp
|
${LIBDIR}/slic3r/Utils/Http.hpp
|
||||||
|
${LIBDIR}/slic3r/Utils/OctoPrint.cpp
|
||||||
|
${LIBDIR}/slic3r/Utils/OctoPrint.hpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(admesh STATIC
|
add_library(admesh STATIC
|
||||||
@ -340,6 +342,7 @@ set(XS_XSP_FILES
|
|||||||
${XSP_DIR}/Surface.xsp
|
${XSP_DIR}/Surface.xsp
|
||||||
${XSP_DIR}/SurfaceCollection.xsp
|
${XSP_DIR}/SurfaceCollection.xsp
|
||||||
${XSP_DIR}/TriangleMesh.xsp
|
${XSP_DIR}/TriangleMesh.xsp
|
||||||
|
${XSP_DIR}/Utils_OctoPrint.xsp
|
||||||
${XSP_DIR}/XS.xsp
|
${XSP_DIR}/XS.xsp
|
||||||
)
|
)
|
||||||
foreach (file ${XS_XSP_FILES})
|
foreach (file ${XS_XSP_FILES})
|
||||||
|
@ -904,10 +904,17 @@ PrintConfigDef::PrintConfigDef()
|
|||||||
def->cli = "octoprint-apikey=s";
|
def->cli = "octoprint-apikey=s";
|
||||||
def->default_value = new ConfigOptionString("");
|
def->default_value = new ConfigOptionString("");
|
||||||
|
|
||||||
|
def = this->add("octoprint_cafile", coString);
|
||||||
|
def->label = "HTTPS CA file";
|
||||||
|
def->tooltip = "Custom CA certificate file can be specified for HTTPS OctoPrint connections, in crt/pem format. "
|
||||||
|
"If left blank, the default OS CA certificate repository is used.";
|
||||||
|
def->cli = "octoprint-cafile=s";
|
||||||
|
def->default_value = new ConfigOptionString("");
|
||||||
|
|
||||||
def = this->add("octoprint_host", coString);
|
def = this->add("octoprint_host", coString);
|
||||||
def->label = L("Host or IP");
|
def->label = L("Hostname, IP or URL");
|
||||||
def->tooltip = L("Slic3r can upload G-code files to OctoPrint. This field should contain "
|
def->tooltip = L("Slic3r can upload G-code files to OctoPrint. This field should contain "
|
||||||
"the hostname or IP address of the OctoPrint instance.");
|
"the hostname, IP address or URL of the OctoPrint instance.");
|
||||||
def->cli = "octoprint-host=s";
|
def->cli = "octoprint-host=s";
|
||||||
def->default_value = new ConfigOptionString("");
|
def->default_value = new ConfigOptionString("");
|
||||||
|
|
||||||
|
@ -684,6 +684,7 @@ class HostConfig : public StaticPrintConfig
|
|||||||
public:
|
public:
|
||||||
ConfigOptionString octoprint_host;
|
ConfigOptionString octoprint_host;
|
||||||
ConfigOptionString octoprint_apikey;
|
ConfigOptionString octoprint_apikey;
|
||||||
|
ConfigOptionString octoprint_cafile;
|
||||||
ConfigOptionString serial_port;
|
ConfigOptionString serial_port;
|
||||||
ConfigOptionInt serial_speed;
|
ConfigOptionInt serial_speed;
|
||||||
|
|
||||||
@ -692,6 +693,7 @@ protected:
|
|||||||
{
|
{
|
||||||
OPT_PTR(octoprint_host);
|
OPT_PTR(octoprint_host);
|
||||||
OPT_PTR(octoprint_apikey);
|
OPT_PTR(octoprint_apikey);
|
||||||
|
OPT_PTR(octoprint_cafile);
|
||||||
OPT_PTR(serial_port);
|
OPT_PTR(serial_port);
|
||||||
OPT_PTR(serial_speed);
|
OPT_PTR(serial_speed);
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,7 @@ REGISTER_CLASS(PresetCollection, "GUI::PresetCollection");
|
|||||||
REGISTER_CLASS(PresetBundle, "GUI::PresetBundle");
|
REGISTER_CLASS(PresetBundle, "GUI::PresetBundle");
|
||||||
REGISTER_CLASS(PresetHints, "GUI::PresetHints");
|
REGISTER_CLASS(PresetHints, "GUI::PresetHints");
|
||||||
REGISTER_CLASS(TabIface, "GUI::Tab");
|
REGISTER_CLASS(TabIface, "GUI::Tab");
|
||||||
|
REGISTER_CLASS(OctoPrint, "OctoPrint");
|
||||||
|
|
||||||
SV* ConfigBase__as_hash(ConfigBase* THIS)
|
SV* ConfigBase__as_hash(ConfigBase* THIS)
|
||||||
{
|
{
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
#include <boost/algorithm/string/predicate.hpp>
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
|
|
||||||
#include <boost/algorithm/string/split.hpp>
|
#include <boost/algorithm/string/split.hpp>
|
||||||
#include <boost/algorithm/string/classification.hpp>
|
#include <boost/algorithm/string/classification.hpp>
|
||||||
|
#include <boost/format.hpp>
|
||||||
|
|
||||||
#if __APPLE__
|
#if __APPLE__
|
||||||
#import <IOKit/pwr_mgt/IOPMLib.h>
|
#import <IOKit/pwr_mgt/IOPMLib.h>
|
||||||
@ -570,4 +570,18 @@ wxString from_u8(std::string str)
|
|||||||
return wxString::FromUTF8(str.c_str());
|
return wxString::FromUTF8(str.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wxWindow *get_widget_by_id(int id)
|
||||||
|
{
|
||||||
|
if (g_wxMainFrame == nullptr) {
|
||||||
|
throw std::runtime_error("Main frame not set");
|
||||||
|
}
|
||||||
|
|
||||||
|
wxWindow *window = g_wxMainFrame->FindWindow(id);
|
||||||
|
if (window == nullptr) {
|
||||||
|
throw std::runtime_error((boost::format("Could not find widget by ID: %1%") % id).str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
|
||||||
} }
|
} }
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "Config.hpp"
|
#include "Config.hpp"
|
||||||
|
|
||||||
class wxApp;
|
class wxApp;
|
||||||
|
class wxWindow;
|
||||||
class wxFrame;
|
class wxFrame;
|
||||||
class wxWindow;
|
class wxWindow;
|
||||||
class wxMenuBar;
|
class wxMenuBar;
|
||||||
@ -118,6 +119,8 @@ wxString L_str(std::string str);
|
|||||||
// Return wxString from std::string in UTF8
|
// Return wxString from std::string in UTF8
|
||||||
wxString from_u8(std::string str);
|
wxString from_u8(std::string str);
|
||||||
|
|
||||||
|
wxWindow *get_widget_by_id(int id);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,7 +224,7 @@ const std::vector<std::string>& Preset::printer_options()
|
|||||||
if (s_opts.empty()) {
|
if (s_opts.empty()) {
|
||||||
s_opts = {
|
s_opts = {
|
||||||
"bed_shape", "z_offset", "gcode_flavor", "use_relative_e_distances", "serial_port", "serial_speed",
|
"bed_shape", "z_offset", "gcode_flavor", "use_relative_e_distances", "serial_port", "serial_speed",
|
||||||
"octoprint_host", "octoprint_apikey", "use_firmware_retraction", "use_volumetric_e", "variable_layer_height",
|
"octoprint_host", "octoprint_apikey", "octoprint_cafile", "use_firmware_retraction", "use_volumetric_e", "variable_layer_height",
|
||||||
"single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode",
|
"single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode",
|
||||||
"between_objects_gcode", "printer_notes"
|
"between_objects_gcode", "printer_notes"
|
||||||
};
|
};
|
||||||
|
105
xs/src/slic3r/Utils/OctoPrint.cpp
Normal file
105
xs/src/slic3r/Utils/OctoPrint.cpp
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#include "OctoPrint.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <boost/format.hpp>
|
||||||
|
|
||||||
|
#include <wx/frame.h>
|
||||||
|
#include <wx/event.h>
|
||||||
|
|
||||||
|
#include "libslic3r/PrintConfig.hpp"
|
||||||
|
#include "slic3r/GUI/GUI.hpp"
|
||||||
|
#include "Http.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
|
||||||
|
OctoPrint::OctoPrint(DynamicPrintConfig *config) :
|
||||||
|
host(config->opt_string("octoprint_host")),
|
||||||
|
apikey(config->opt_string("octoprint_apikey")),
|
||||||
|
cafile(config->opt_string("octoprint_cafile"))
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::string OctoPrint::test() const
|
||||||
|
{
|
||||||
|
// Since the request is performed synchronously here,
|
||||||
|
// it is ok to refer to `res` from within the closure
|
||||||
|
std::string res;
|
||||||
|
|
||||||
|
auto http = Http::get(std::move(make_url("api/version")));
|
||||||
|
set_auth(http);
|
||||||
|
http.on_error([&](std::string, std::string error, unsigned status) {
|
||||||
|
res = format_error(error, status);
|
||||||
|
})
|
||||||
|
.perform_sync();
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OctoPrint::send_gcode(int windowId, int completeEvt, int errorEvt, const std::string &filename, bool print) const
|
||||||
|
{
|
||||||
|
auto http = Http::post(std::move(make_url("api/files/local")));
|
||||||
|
set_auth(http);
|
||||||
|
http.form_add("print", print ? "true" : "false")
|
||||||
|
.form_add_file("file", filename)
|
||||||
|
.on_complete([=](std::string body, unsigned status) {
|
||||||
|
wxWindow *window = GUI::get_widget_by_id(windowId);
|
||||||
|
wxCommandEvent* evt = new wxCommandEvent(completeEvt);
|
||||||
|
evt->SetString("G-code file successfully uploaded to the OctoPrint server");
|
||||||
|
evt->SetInt(100);
|
||||||
|
wxQueueEvent(window, evt);
|
||||||
|
})
|
||||||
|
.on_error([=](std::string body, std::string error, unsigned status) {
|
||||||
|
wxWindow *window = GUI::get_widget_by_id(windowId);
|
||||||
|
|
||||||
|
wxCommandEvent* evt_complete = new wxCommandEvent(completeEvt);
|
||||||
|
evt_complete->SetInt(100);
|
||||||
|
wxQueueEvent(window, evt_complete);
|
||||||
|
|
||||||
|
wxCommandEvent* evt_error = new wxCommandEvent(errorEvt);
|
||||||
|
evt_error->SetString(wxString::Format("Error while uploading to the OctoPrint server: %s", format_error(error, status)));
|
||||||
|
wxQueueEvent(window, evt_error);
|
||||||
|
})
|
||||||
|
.perform();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OctoPrint::set_auth(Http &http) const
|
||||||
|
{
|
||||||
|
http.header("X-Api-Key", apikey);
|
||||||
|
|
||||||
|
if (! cafile.empty()) {
|
||||||
|
http.ca_file(cafile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string OctoPrint::make_url(const std::string &path) const
|
||||||
|
{
|
||||||
|
if (host.find("http://") == 0 || host.find("https://") == 0) {
|
||||||
|
if (host.back() == '/') {
|
||||||
|
return std::move((boost::format("%1%%2%") % host % path).str());
|
||||||
|
} else {
|
||||||
|
return std::move((boost::format("%1%/%2%") % host % path).str());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return std::move((boost::format("http://%1%/%2%") % host % path).str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string OctoPrint::format_error(std::string error, unsigned status)
|
||||||
|
{
|
||||||
|
if (status != 0) {
|
||||||
|
std::string res{"HTTP "};
|
||||||
|
res.append(std::to_string(status));
|
||||||
|
|
||||||
|
if (status == 401) {
|
||||||
|
res.append(": Invalid API key");
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::move(res);
|
||||||
|
} else {
|
||||||
|
return std::move(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
35
xs/src/slic3r/Utils/OctoPrint.hpp
Normal file
35
xs/src/slic3r/Utils/OctoPrint.hpp
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#ifndef slic3r_OctoPrint_hpp_
|
||||||
|
#define slic3r_OctoPrint_hpp_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "Http.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
|
||||||
|
class DynamicPrintConfig;
|
||||||
|
class Http;
|
||||||
|
|
||||||
|
class OctoPrint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OctoPrint(DynamicPrintConfig *config);
|
||||||
|
|
||||||
|
std::string test() const;
|
||||||
|
// XXX: style
|
||||||
|
void send_gcode(int windowId, int completeEvt, int errorEvt, const std::string &filename, bool print = false) const;
|
||||||
|
private:
|
||||||
|
std::string host;
|
||||||
|
std::string apikey;
|
||||||
|
std::string cafile;
|
||||||
|
|
||||||
|
void set_auth(Http &http) const;
|
||||||
|
std::string make_url(const std::string &path) const;
|
||||||
|
static std::string format_error(std::string error, unsigned status);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
14
xs/xsp/Utils_OctoPrint.xsp
Normal file
14
xs/xsp/Utils_OctoPrint.xsp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
%module{Slic3r::XS};
|
||||||
|
|
||||||
|
%{
|
||||||
|
#include <xsinit.h>
|
||||||
|
#include "slic3r/Utils/OctoPrint.hpp"
|
||||||
|
%}
|
||||||
|
|
||||||
|
%name{Slic3r::OctoPrint} class OctoPrint {
|
||||||
|
OctoPrint(DynamicPrintConfig *config);
|
||||||
|
~OctoPrint();
|
||||||
|
|
||||||
|
std::string test() const;
|
||||||
|
void send_gcode(int windowId, int completeEvt, int errorEvt, std::string filename, bool print = false) const;
|
||||||
|
};
|
@ -236,6 +236,10 @@ Ref<PresetHints> O_OBJECT_SLIC3R_T
|
|||||||
TabIface* O_OBJECT_SLIC3R
|
TabIface* O_OBJECT_SLIC3R
|
||||||
Ref<TabIface> O_OBJECT_SLIC3R_T
|
Ref<TabIface> O_OBJECT_SLIC3R_T
|
||||||
|
|
||||||
|
OctoPrint* O_OBJECT_SLIC3R
|
||||||
|
Ref<OctoPrint> O_OBJECT_SLIC3R_T
|
||||||
|
Clone<OctoPrint> O_OBJECT_SLIC3R_T
|
||||||
|
|
||||||
Axis T_UV
|
Axis T_UV
|
||||||
ExtrusionLoopRole T_UV
|
ExtrusionLoopRole T_UV
|
||||||
ExtrusionRole T_UV
|
ExtrusionRole T_UV
|
||||||
|
Loading…
Reference in New Issue
Block a user