Integration with Octoprint. #1826
This commit is contained in:
parent
eba19aaba4
commit
efe7d5f857
1
Build.PL
1
Build.PL
@ -27,6 +27,7 @@ my %prereqs = qw(
|
|||||||
);
|
);
|
||||||
my %recommends = qw(
|
my %recommends = qw(
|
||||||
Class::XSAccessor 0
|
Class::XSAccessor 0
|
||||||
|
LWP::UserAgent 0
|
||||||
XML::SAX::ExpatXS 0
|
XML::SAX::ExpatXS 0
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ use Slic3r::GUI::SimpleTab;
|
|||||||
use Slic3r::GUI::Tab;
|
use Slic3r::GUI::Tab;
|
||||||
|
|
||||||
our $have_OpenGL = eval "use Slic3r::GUI::PreviewCanvas; 1";
|
our $have_OpenGL = eval "use Slic3r::GUI::PreviewCanvas; 1";
|
||||||
|
our $have_LWP = eval "use LWP::UserAgent; 1";
|
||||||
|
|
||||||
use Wx 0.9901 qw(:bitmap :dialog :icon :id :misc :systemsettings :toplevelwindow
|
use Wx 0.9901 qw(:bitmap :dialog :icon :id :misc :systemsettings :toplevelwindow
|
||||||
:filedialog);
|
:filedialog);
|
||||||
@ -228,7 +229,7 @@ sub have_version_check {
|
|||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
|
|
||||||
# return an explicit 0
|
# return an explicit 0
|
||||||
return ($Slic3r::have_threads && $Slic3r::build && eval "use LWP::UserAgent; 1") || 0;
|
return ($Slic3r::have_threads && $Slic3r::build && $have_LWP) || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub check_version {
|
sub check_version {
|
||||||
|
@ -48,6 +48,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(qw(
|
$self->{config} = Slic3r::Config->new_from_defaults(qw(
|
||||||
bed_shape complete_objects extruder_clearance_radius skirts skirt_distance brim_width
|
bed_shape complete_objects extruder_clearance_radius skirts skirt_distance brim_width
|
||||||
|
octoprint_host octoprint_apikey
|
||||||
));
|
));
|
||||||
$self->{model} = Slic3r::Model->new;
|
$self->{model} = Slic3r::Model->new;
|
||||||
$self->{print} = Slic3r::Print->new;
|
$self->{print} = Slic3r::Print->new;
|
||||||
@ -181,9 +182,11 @@ sub new {
|
|||||||
|
|
||||||
# right pane buttons
|
# right pane buttons
|
||||||
$self->{btn_export_gcode} = Wx::Button->new($self, -1, "Export G-code…", wxDefaultPosition, [-1, 30], wxBU_LEFT);
|
$self->{btn_export_gcode} = Wx::Button->new($self, -1, "Export G-code…", wxDefaultPosition, [-1, 30], wxBU_LEFT);
|
||||||
|
$self->{btn_send_gcode} = Wx::Button->new($self, -1, "Send to printer", wxDefaultPosition, [-1, 30], wxBU_LEFT);
|
||||||
$self->{btn_export_stl} = Wx::Button->new($self, -1, "Export STL…", wxDefaultPosition, [-1, 30], wxBU_LEFT);
|
$self->{btn_export_stl} = Wx::Button->new($self, -1, "Export STL…", wxDefaultPosition, [-1, 30], wxBU_LEFT);
|
||||||
#$self->{btn_export_gcode}->SetFont($Slic3r::GUI::small_font);
|
#$self->{btn_export_gcode}->SetFont($Slic3r::GUI::small_font);
|
||||||
#$self->{btn_export_stl}->SetFont($Slic3r::GUI::small_font);
|
#$self->{btn_export_stl}->SetFont($Slic3r::GUI::small_font);
|
||||||
|
$self->{btn_send_gcode}->Hide;
|
||||||
|
|
||||||
if ($Slic3r::GUI::have_button_icons) {
|
if ($Slic3r::GUI::have_button_icons) {
|
||||||
my %icons = qw(
|
my %icons = qw(
|
||||||
@ -192,6 +195,7 @@ sub new {
|
|||||||
reset cross.png
|
reset cross.png
|
||||||
arrange bricks.png
|
arrange bricks.png
|
||||||
export_gcode cog_go.png
|
export_gcode cog_go.png
|
||||||
|
send_gcode cog_go.png
|
||||||
export_stl brick_go.png
|
export_stl brick_go.png
|
||||||
|
|
||||||
increase add.png
|
increase add.png
|
||||||
@ -213,6 +217,10 @@ sub new {
|
|||||||
$self->export_gcode;
|
$self->export_gcode;
|
||||||
Slic3r::thread_cleanup();
|
Slic3r::thread_cleanup();
|
||||||
});
|
});
|
||||||
|
EVT_BUTTON($self, $self->{btn_send_gcode}, sub {
|
||||||
|
$self->{send_gcode_file} = $self->export_gcode(Wx::StandardPaths::Get->GetTempDir());
|
||||||
|
Slic3r::thread_cleanup();
|
||||||
|
});
|
||||||
#EVT_BUTTON($self, $self->{btn_export_stl}, \&export_stl);
|
#EVT_BUTTON($self, $self->{btn_export_stl}, \&export_stl);
|
||||||
|
|
||||||
if ($self->{htoolbar}) {
|
if ($self->{htoolbar}) {
|
||||||
@ -355,6 +363,7 @@ sub new {
|
|||||||
my $buttons_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
|
my $buttons_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
|
||||||
$buttons_sizer->AddStretchSpacer(1);
|
$buttons_sizer->AddStretchSpacer(1);
|
||||||
$buttons_sizer->Add($self->{btn_export_stl}, 0, wxALIGN_RIGHT, 0);
|
$buttons_sizer->Add($self->{btn_export_stl}, 0, wxALIGN_RIGHT, 0);
|
||||||
|
$buttons_sizer->Add($self->{btn_send_gcode}, 0, wxALIGN_RIGHT, 0);
|
||||||
$buttons_sizer->Add($self->{btn_export_gcode}, 0, wxALIGN_RIGHT, 0);
|
$buttons_sizer->Add($self->{btn_export_gcode}, 0, wxALIGN_RIGHT, 0);
|
||||||
|
|
||||||
my $right_sizer = Wx::BoxSizer->new(wxVERTICAL);
|
my $right_sizer = Wx::BoxSizer->new(wxVERTICAL);
|
||||||
@ -944,7 +953,7 @@ sub resume_background_process {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub export_gcode {
|
sub export_gcode {
|
||||||
my $self = shift;
|
my ($self, $output_file) = @_;
|
||||||
|
|
||||||
return if !@{$self->{objects}};
|
return if !@{$self->{objects}};
|
||||||
|
|
||||||
@ -976,14 +985,14 @@ sub export_gcode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# select output file
|
# select output file
|
||||||
$self->{export_gcode_output_file} = $main::opt{output};
|
if ($output_file) {
|
||||||
{
|
$self->{export_gcode_output_file} = $self->{print}->expanded_output_filepath($output_file);
|
||||||
my $default_output_file = $self->{print}->expanded_output_filepath($self->{export_gcode_output_file});
|
} else {
|
||||||
|
my $default_output_file = $self->{print}->expanded_output_filepath($main::opt{output});
|
||||||
my $dlg = Wx::FileDialog->new($self, 'Save G-code file as:', wxTheApp->output_path(dirname($default_output_file)),
|
my $dlg = Wx::FileDialog->new($self, 'Save G-code file as:', wxTheApp->output_path(dirname($default_output_file)),
|
||||||
basename($default_output_file), &Slic3r::GUI::FILE_WILDCARDS->{gcode}, wxFD_SAVE);
|
basename($default_output_file), &Slic3r::GUI::FILE_WILDCARDS->{gcode}, wxFD_SAVE);
|
||||||
if ($dlg->ShowModal != wxID_OK) {
|
if ($dlg->ShowModal != wxID_OK) {
|
||||||
$dlg->Destroy;
|
$dlg->Destroy;
|
||||||
$self->{export_gcode_output_file} = undef;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$Slic3r::GUI::Settings->{_}{last_output_path} = dirname($dlg->GetPath);
|
$Slic3r::GUI::Settings->{_}{last_output_path} = dirname($dlg->GetPath);
|
||||||
@ -1011,6 +1020,8 @@ sub export_gcode {
|
|||||||
my $result = !Slic3r::GUI::catch_error($self);
|
my $result = !Slic3r::GUI::catch_error($self);
|
||||||
$self->on_export_completed($result);
|
$self->on_export_completed($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $self->{export_gcode_output_file};
|
||||||
}
|
}
|
||||||
|
|
||||||
# This gets called only if we have threads.
|
# This gets called only if we have threads.
|
||||||
@ -1072,14 +1083,49 @@ sub on_export_completed {
|
|||||||
$self->{export_thread} = undef;
|
$self->{export_thread} = undef;
|
||||||
|
|
||||||
my $message;
|
my $message;
|
||||||
|
my $send_gcode = 0;
|
||||||
if ($result) {
|
if ($result) {
|
||||||
|
if ($self->{send_gcode_file}) {
|
||||||
|
$message = "Sending G-code file to the Octoprint server...";
|
||||||
|
$send_gcode = 1;
|
||||||
|
} else {
|
||||||
$message = "G-code file exported to " . $self->{export_gcode_output_file};
|
$message = "G-code file exported to " . $self->{export_gcode_output_file};
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$message = "Export failed";
|
$message = "Export failed";
|
||||||
}
|
}
|
||||||
$self->{export_gcode_output_file} = undef;
|
$self->{export_gcode_output_file} = undef;
|
||||||
$self->statusbar->SetStatusText($message);
|
$self->statusbar->SetStatusText($message);
|
||||||
wxTheApp->notify($message);
|
wxTheApp->notify($message);
|
||||||
|
|
||||||
|
$self->send_gcode if $send_gcode;
|
||||||
|
$self->{send_gcode_file} = undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub send_gcode {
|
||||||
|
my ($self) = @_;
|
||||||
|
|
||||||
|
$self->statusbar->StartBusy;
|
||||||
|
|
||||||
|
my $ua = LWP::UserAgent->new;
|
||||||
|
$ua->timeout(10);
|
||||||
|
|
||||||
|
my $res = $ua->post(
|
||||||
|
"http://" . $self->{config}->octoprint_host . "/api/files/local",
|
||||||
|
Content_Type => 'form-data',
|
||||||
|
'X-Api-Key' => $self->{config}->octoprint_apikey,
|
||||||
|
Content => [
|
||||||
|
fn => [$self->{send_gcode_file}],
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
$self->statusbar->StopBusy;
|
||||||
|
|
||||||
|
if ($res->is_success) {
|
||||||
|
$self->statusbar->SetStatusText("G-code file successfully uploaded to the Octoprint server");
|
||||||
|
} else {
|
||||||
|
$self->statusbar->SetStatusText("Error while uploading to the Octoprint server: " . $res->status_line);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub export_stl {
|
sub export_stl {
|
||||||
@ -1208,6 +1254,13 @@ sub on_config_change {
|
|||||||
$self->{canvas}->update_bed_size;
|
$self->{canvas}->update_bed_size;
|
||||||
$self->{canvas3D}->update_bed_size if $self->{canvas3D};
|
$self->{canvas3D}->update_bed_size if $self->{canvas3D};
|
||||||
$self->update;
|
$self->update;
|
||||||
|
} elsif ($opt_key eq 'octoprint_host') {
|
||||||
|
if ($config->get('octoprint_host')) {
|
||||||
|
$self->{btn_send_gcode}->Show;
|
||||||
|
} else {
|
||||||
|
$self->{btn_send_gcode}->Hide;
|
||||||
|
}
|
||||||
|
$self->Layout;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1313,7 +1366,7 @@ sub object_list_changed {
|
|||||||
my $have_objects = @{$self->{objects}} ? 1 : 0;
|
my $have_objects = @{$self->{objects}} ? 1 : 0;
|
||||||
my $method = $have_objects ? 'Enable' : 'Disable';
|
my $method = $have_objects ? 'Enable' : 'Disable';
|
||||||
$self->{"btn_$_"}->$method
|
$self->{"btn_$_"}->$method
|
||||||
for grep $self->{"btn_$_"}, qw(reset arrange export_gcode export_stl);
|
for grep $self->{"btn_$_"}, qw(reset arrange export_gcode export_stl send_gcode);
|
||||||
|
|
||||||
if ($self->{htoolbar}) {
|
if ($self->{htoolbar}) {
|
||||||
$self->{htoolbar}->EnableTool($_, $have_objects)
|
$self->{htoolbar}->EnableTool($_, $have_objects)
|
||||||
|
@ -923,6 +923,7 @@ sub build {
|
|||||||
$self->init_config_options(qw(
|
$self->init_config_options(qw(
|
||||||
bed_shape z_offset
|
bed_shape z_offset
|
||||||
gcode_flavor use_relative_e_distances
|
gcode_flavor use_relative_e_distances
|
||||||
|
octoprint_host octoprint_apikey
|
||||||
use_firmware_retraction pressure_advance vibration_limit
|
use_firmware_retraction pressure_advance vibration_limit
|
||||||
start_gcode end_gcode layer_gcode toolchange_gcode
|
start_gcode end_gcode layer_gcode toolchange_gcode
|
||||||
nozzle_diameter extruder_offset
|
nozzle_diameter extruder_offset
|
||||||
@ -996,6 +997,11 @@ sub build {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
my $optgroup = $page->new_optgroup('Octoprint upload');
|
||||||
|
$optgroup->append_single_option_line('octoprint_host');
|
||||||
|
$optgroup->append_single_option_line('octoprint_apikey');
|
||||||
|
}
|
||||||
{
|
{
|
||||||
my $optgroup = $page->new_optgroup('Advanced');
|
my $optgroup = $page->new_optgroup('Advanced');
|
||||||
$optgroup->append_single_option_line('use_firmware_retraction');
|
$optgroup->append_single_option_line('use_firmware_retraction');
|
||||||
@ -1129,6 +1135,8 @@ sub _update {
|
|||||||
|
|
||||||
my $config = $self->{config};
|
my $config = $self->{config};
|
||||||
|
|
||||||
|
$self->get_field('octoprint_apikey')->toggle($config->get('octoprint_host'));
|
||||||
|
|
||||||
my $have_multiple_extruders = $self->{extruders_count} > 1;
|
my $have_multiple_extruders = $self->{extruders_count} > 1;
|
||||||
$self->get_field('toolchange_gcode')->toggle($have_multiple_extruders);
|
$self->get_field('toolchange_gcode')->toggle($have_multiple_extruders);
|
||||||
|
|
||||||
@ -1319,8 +1327,8 @@ sub config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# apply preset values on top of defaults
|
# apply preset values on top of defaults
|
||||||
|
my $config = Slic3r::Config->new_from_defaults(@$keys);
|
||||||
my $external_config = Slic3r::Config->load($self->file);
|
my $external_config = Slic3r::Config->load($self->file);
|
||||||
my $config = Slic3r::Config->new;
|
|
||||||
$config->set($_, $external_config->get($_))
|
$config->set($_, $external_config->get($_))
|
||||||
for grep $external_config->has($_), @$keys;
|
for grep $external_config->has($_), @$keys;
|
||||||
|
|
||||||
|
@ -498,6 +498,16 @@ PrintConfigDef::build_def() {
|
|||||||
Options["nozzle_diameter"].sidetext = "mm";
|
Options["nozzle_diameter"].sidetext = "mm";
|
||||||
Options["nozzle_diameter"].cli = "nozzle-diameter=f@";
|
Options["nozzle_diameter"].cli = "nozzle-diameter=f@";
|
||||||
|
|
||||||
|
Options["octoprint_apikey"].type = coString;
|
||||||
|
Options["octoprint_apikey"].label = "API Key";
|
||||||
|
Options["octoprint_apikey"].tooltip = "Slic3r can upload G-code files to Octoprint. This field should contain the API Key required for authentication.";
|
||||||
|
Options["octoprint_apikey"].cli = "octoprint-apikey=s";
|
||||||
|
|
||||||
|
Options["octoprint_host"].type = coString;
|
||||||
|
Options["octoprint_host"].label = "Host or IP";
|
||||||
|
Options["octoprint_host"].tooltip = "Slic3r can upload G-code files to Octoprint. This field should contain the hostname or IP address of the Octoprint instance.";
|
||||||
|
Options["octoprint_host"].cli = "octoprint-host=s";
|
||||||
|
|
||||||
Options["only_retract_when_crossing_perimeters"].type = coBool;
|
Options["only_retract_when_crossing_perimeters"].type = coBool;
|
||||||
Options["only_retract_when_crossing_perimeters"].label = "Only retract when crossing perimeters";
|
Options["only_retract_when_crossing_perimeters"].label = "Only retract when crossing perimeters";
|
||||||
Options["only_retract_when_crossing_perimeters"].tooltip = "Disables retraction when the travel path does not exceed the upper layer's perimeters (and thus any ooze will be probably invisible).";
|
Options["only_retract_when_crossing_perimeters"].tooltip = "Disables retraction when the travel path does not exceed the upper layer's perimeters (and thus any ooze will be probably invisible).";
|
||||||
|
@ -582,7 +582,27 @@ class PrintConfig : public GCodeConfig
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
class FullPrintConfig : public PrintObjectConfig, public PrintRegionConfig, public PrintConfig
|
class HostConfig : public virtual StaticPrintConfig
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ConfigOptionString octoprint_host;
|
||||||
|
ConfigOptionString octoprint_apikey;
|
||||||
|
|
||||||
|
HostConfig() : StaticPrintConfig() {
|
||||||
|
this->octoprint_host.value = "";
|
||||||
|
this->octoprint_apikey.value = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
ConfigOption* option(const t_config_option_key opt_key, bool create = false) {
|
||||||
|
if (opt_key == "octoprint_host") return &this->octoprint_host;
|
||||||
|
if (opt_key == "octoprint_apikey") return &this->octoprint_apikey;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class FullPrintConfig
|
||||||
|
: public PrintObjectConfig, public PrintRegionConfig, public PrintConfig, public HostConfig
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ConfigOption* option(const t_config_option_key opt_key, bool create = false) {
|
ConfigOption* option(const t_config_option_key opt_key, bool create = false) {
|
||||||
@ -590,6 +610,7 @@ class FullPrintConfig : public PrintObjectConfig, public PrintRegionConfig, publ
|
|||||||
if ((opt = PrintObjectConfig::option(opt_key, create)) != NULL) return opt;
|
if ((opt = PrintObjectConfig::option(opt_key, create)) != NULL) return opt;
|
||||||
if ((opt = PrintRegionConfig::option(opt_key, create)) != NULL) return opt;
|
if ((opt = PrintRegionConfig::option(opt_key, create)) != NULL) return opt;
|
||||||
if ((opt = PrintConfig::option(opt_key, create)) != NULL) return opt;
|
if ((opt = PrintConfig::option(opt_key, create)) != NULL) return opt;
|
||||||
|
if ((opt = HostConfig::option(opt_key, create)) != NULL) return opt;
|
||||||
return NULL;
|
return NULL;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user