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
|
||||
# assign menubar to frame after appending items, otherwise special items
|
||||
# will not be handled correctly
|
||||
@ -424,6 +432,8 @@ sub _init_menubar {
|
||||
# (Select application language from the list of installed languages)
|
||||
Slic3r::GUI::add_debug_menu($menubar, $self->{lang_ch_event});
|
||||
$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);
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ sub new {
|
||||
my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
|
||||
$self->{config} = Slic3r::Config::new_from_defaults_keys([qw(
|
||||
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
|
||||
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);
|
||||
|
||||
$self->do_print if $do_print;
|
||||
|
||||
# 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->{send_gcode_file} = undef;
|
||||
$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;
|
||||
$filament_stats = { map { $filament_names->[$_] => $filament_stats->{$_} } keys %$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 {
|
||||
|
@ -201,6 +201,8 @@ add_library(libslic3r_gui STATIC
|
||||
${LIBDIR}/slic3r/GUI/wxExtensions.hpp
|
||||
${LIBDIR}/slic3r/Utils/Http.cpp
|
||||
${LIBDIR}/slic3r/Utils/Http.hpp
|
||||
${LIBDIR}/slic3r/Utils/OctoPrint.cpp
|
||||
${LIBDIR}/slic3r/Utils/OctoPrint.hpp
|
||||
)
|
||||
|
||||
add_library(admesh STATIC
|
||||
@ -340,6 +342,7 @@ set(XS_XSP_FILES
|
||||
${XSP_DIR}/Surface.xsp
|
||||
${XSP_DIR}/SurfaceCollection.xsp
|
||||
${XSP_DIR}/TriangleMesh.xsp
|
||||
${XSP_DIR}/Utils_OctoPrint.xsp
|
||||
${XSP_DIR}/XS.xsp
|
||||
)
|
||||
foreach (file ${XS_XSP_FILES})
|
||||
|
@ -904,10 +904,17 @@ PrintConfigDef::PrintConfigDef()
|
||||
def->cli = "octoprint-apikey=s";
|
||||
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->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 "
|
||||
"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->default_value = new ConfigOptionString("");
|
||||
|
||||
|
@ -684,6 +684,7 @@ class HostConfig : public StaticPrintConfig
|
||||
public:
|
||||
ConfigOptionString octoprint_host;
|
||||
ConfigOptionString octoprint_apikey;
|
||||
ConfigOptionString octoprint_cafile;
|
||||
ConfigOptionString serial_port;
|
||||
ConfigOptionInt serial_speed;
|
||||
|
||||
@ -692,6 +693,7 @@ protected:
|
||||
{
|
||||
OPT_PTR(octoprint_host);
|
||||
OPT_PTR(octoprint_apikey);
|
||||
OPT_PTR(octoprint_cafile);
|
||||
OPT_PTR(serial_port);
|
||||
OPT_PTR(serial_speed);
|
||||
}
|
||||
|
@ -64,6 +64,7 @@ REGISTER_CLASS(PresetCollection, "GUI::PresetCollection");
|
||||
REGISTER_CLASS(PresetBundle, "GUI::PresetBundle");
|
||||
REGISTER_CLASS(PresetHints, "GUI::PresetHints");
|
||||
REGISTER_CLASS(TabIface, "GUI::Tab");
|
||||
REGISTER_CLASS(OctoPrint, "OctoPrint");
|
||||
|
||||
SV* ConfigBase__as_hash(ConfigBase* THIS)
|
||||
{
|
||||
|
@ -5,9 +5,9 @@
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#if __APPLE__
|
||||
#import <IOKit/pwr_mgt/IOPMLib.h>
|
||||
@ -570,4 +570,18 @@ wxString from_u8(std::string 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"
|
||||
|
||||
class wxApp;
|
||||
class wxWindow;
|
||||
class wxFrame;
|
||||
class wxWindow;
|
||||
class wxMenuBar;
|
||||
@ -118,6 +119,8 @@ wxString L_str(std::string str);
|
||||
// Return wxString from std::string in UTF8
|
||||
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()) {
|
||||
s_opts = {
|
||||
"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",
|
||||
"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
|
||||
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
|
||||
ExtrusionLoopRole T_UV
|
||||
ExtrusionRole T_UV
|
||||
|
Loading…
Reference in New Issue
Block a user