Add support for RepetierServer

This commit is contained in:
Boris Pruessmann 2020-06-13 10:57:24 +02:00 committed by Merill
parent de57391b79
commit d7f0cc71e6
11 changed files with 288 additions and 9 deletions

View File

@ -2744,7 +2744,9 @@ void GCode::append_full_config(const Print &print, std::string &str)
"compatible_prints",
"print_host",
"printhost_apikey",
"printhost_cafile"
"printhost_cafile",
"repetier_group",
"repetier_slug"
};
assert(std::is_sorted(banned_keys.begin(), banned_keys.end()));
auto is_banned = [banned_keys](const std::string &key) {

View File

@ -148,7 +148,20 @@ void PrintConfigDef::init_common_params()
"the API Key or the password required for authentication.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionString(""));
def = this->add("repetier_slug", coString);
def->label = L("Repetier Printer");
def->tooltip = L("Name of the Repetier printer");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionString(""));
def = this->add("repetier_group", coString);
def->label = L("Repetier Group");
def->tooltip = L("Name of the Repetier group that the G-code file will be sent to.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionString(""));
def = this->add("printhost_cafile", coString);
def->label = L("HTTPS CA File");
def->category = OptionCategory::general;
@ -2277,10 +2290,12 @@ void PrintConfigDef::init_fff_params()
def->enum_values.push_back("duet");
def->enum_values.push_back("flashair");
def->enum_values.push_back("astrobox");
def->enum_values.push_back("repetier");
def->enum_labels.push_back("OctoPrint");
def->enum_labels.push_back("Duet");
def->enum_labels.push_back("FlashAir");
def->enum_labels.push_back("AstroBox");
def->enum_labels.push_back("Repetier");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionEnum<PrintHostType>(htOctoPrint));

View File

@ -64,7 +64,7 @@ enum GCodeFlavor : uint8_t {
};
enum PrintHostType {
htOctoPrint, htDuet, htFlashAir, htAstroBox
htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier
};
enum InfillPattern {
@ -174,6 +174,7 @@ template<> inline const t_config_enum_values& ConfigOptionEnum<PrintHostType>::g
keys_map["duet"] = htDuet;
keys_map["flashair"] = htFlashAir;
keys_map["astrobox"] = htAstroBox;
keys_map["repetier"] = htRepetier;
}
return keys_map;
}
@ -1276,6 +1277,8 @@ public:
ConfigOptionString print_host;
ConfigOptionString printhost_apikey;
ConfigOptionString printhost_cafile;
ConfigOptionString repetier_slug;
ConfigOptionString repetier_group;
ConfigOptionString serial_port;
ConfigOptionInt serial_speed;
@ -1286,6 +1289,8 @@ protected:
OPT_PTR(print_host);
OPT_PTR(printhost_apikey);
OPT_PTR(printhost_cafile);
OPT_PTR(repetier_slug);
OPT_PTR(repetier_group);
OPT_PTR(serial_port);
OPT_PTR(serial_speed);
}

View File

@ -180,6 +180,8 @@ set(SLIC3R_GUI_SOURCES
Utils/FlashAir.hpp
Utils/AstroBox.cpp
Utils/AstroBox.hpp
Utils/Repetier.cpp
Utils/Repetier.hpp
Utils/PrintHost.cpp
Utils/PrintHost.hpp
Utils/Bonjour.cpp

View File

@ -2066,7 +2066,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
"complete_objects_one_skirt",
"duplicate_distance", "extruder_clearance_radius", "skirts", "skirt_distance", "skirt_height",
"brim_width", "variable_layer_height", "serial_port", "serial_speed", "host_type", "print_host",
"printhost_apikey", "printhost_cafile", "nozzle_diameter", "single_extruder_multi_material",
"printhost_apikey", "printhost_cafile", "repetier_slug", "repetier_group", "nozzle_diameter", "single_extruder_multi_material",
"wipe_tower", "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim",
"extruder_colour", "filament_colour", "max_print_height", "printer_model", "printer_technology",
// These values are necessary to construct SlicingParameters by the Canvas3D variable layer height editor.

View File

@ -613,7 +613,7 @@ const std::vector<std::string>& Preset::printer_options()
"bed_shape", "bed_custom_texture", "bed_custom_model", "z_offset", "gcode_flavor", "use_relative_e_distances", "serial_port", "serial_speed",
"use_firmware_retraction", "use_volumetric_e", "variable_layer_height",
"min_length",
"host_type", "print_host", "printhost_apikey", "printhost_cafile",
"host_type", "print_host", "printhost_apikey", "printhost_cafile", "repetier_slug", "repetier_group",
"single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode",
"feature_gcode",
"between_objects_gcode", "printer_vendor", "printer_model", "printer_variant", "printer_notes", "cooling_tube_retraction",
@ -751,7 +751,7 @@ const std::vector<std::string>& Preset::sla_printer_options()
"gamma_correction",
"min_exposure_time", "max_exposure_time",
"min_initial_exposure_time", "max_initial_exposure_time",
"print_host", "printhost_apikey", "printhost_cafile",
"print_host", "printhost_apikey", "printhost_cafile", "repetier_slug", "repetier_group",
"printer_notes",
"inherits",
"thumbnails",
@ -891,15 +891,21 @@ static ProfileHostParams profile_host_params_same_or_anonymized(const DynamicPri
auto opt_print_host_old = cfg_old.option<ConfigOptionString>("print_host");
auto opt_printhost_apikey_old = cfg_old.option<ConfigOptionString>("printhost_apikey");
auto opt_printhost_cafile_old = cfg_old.option<ConfigOptionString>("printhost_cafile");
auto opt_repetier_slug_old = cfg_old.option<ConfigOptionString>("repetier_slug");
auto opt_repetier_group_old = cfg_old.option<ConfigOptionString>("repetier_group");
auto opt_print_host_new = cfg_new.option<ConfigOptionString>("print_host");
auto opt_printhost_apikey_new = cfg_new.option<ConfigOptionString>("printhost_apikey");
auto opt_printhost_cafile_new = cfg_new.option<ConfigOptionString>("printhost_cafile");
auto opt_repetier_slug_new = cfg_new.option<ConfigOptionString>("repetier_slug");
auto opt_repetier_group_new = cfg_new.option<ConfigOptionString>("repetier_group");
// If the new print host data is undefined, use the old data.
bool new_print_host_undefined = (opt_print_host_new == nullptr || opt_print_host_new ->empty()) &&
(opt_printhost_apikey_new == nullptr || opt_printhost_apikey_new ->empty()) &&
(opt_printhost_cafile_new == nullptr || opt_printhost_cafile_new ->empty());
(opt_printhost_cafile_new == nullptr || opt_printhost_cafile_new ->empty()) &&
(opt_repetier_slug_new == nullptr || opt_repetier_slug_new ->empty()) &&
(opt_repetier_group_new == nullptr || opt_repetier_group_new ->empty());
if (new_print_host_undefined)
return ProfileHostParams::Anonymized;
@ -907,8 +913,9 @@ static ProfileHostParams profile_host_params_same_or_anonymized(const DynamicPri
return ((l == nullptr || l->empty()) && (r == nullptr || r->empty())) ||
(l != nullptr && r != nullptr && l->value == r->value);
};
return (opt_same(opt_print_host_old, opt_print_host_new) && opt_same(opt_printhost_apikey_old, opt_printhost_apikey_new) &&
opt_same(opt_printhost_cafile_old, opt_printhost_cafile_new)) ? ProfileHostParams::Same : ProfileHostParams::Different;
return (opt_same(opt_print_host_old, opt_print_host_new) && opt_same(opt_printhost_apikey_old, opt_printhost_apikey_new) &&
opt_same(opt_printhost_cafile_old, opt_printhost_cafile_new) && opt_same(opt_repetier_slug_old, opt_repetier_slug_new) &&
opt_same(opt_repetier_group_old, opt_repetier_group_new)) ? ProfileHostParams::Same : ProfileHostParams::Different;
}
static bool profile_print_params_same(const DynamicPrintConfig &cfg_old, const DynamicPrintConfig &cfg_new)
@ -920,7 +927,7 @@ static bool profile_print_params_same(const DynamicPrintConfig &cfg_old, const D
"compatible_printers", "compatible_printers_condition", "inherits",
"print_settings_id", "filament_settings_id", "sla_print_settings_id", "sla_material_settings_id", "printer_settings_id",
"printer_model", "printer_variant", "default_print_profile", "default_filament_profile", "default_sla_print_profile", "default_sla_material_profile",
"print_host", "printhost_apikey", "printhost_cafile" })
"print_host", "printhost_apikey", "repetier_slug", "repetier_group", "printhost_cafile" })
diff.erase(std::remove(diff.begin(), diff.end(), key), diff.end());
// Preset with the same name as stored inside the config exists.
return diff.empty() && profile_host_params_same_or_anonymized(cfg_old, cfg_new) != ProfileHostParams::Different;
@ -970,6 +977,8 @@ Preset& PresetCollection::load_external_preset(
opt_update("print_host");
opt_update("printhost_apikey");
opt_update("printhost_cafile");
opt_update("repetier_slug");
opt_update("repetier_group");
}
}
// Update the "inherits" field.

View File

@ -526,6 +526,8 @@ DynamicPrintConfig PresetBundle::full_config_secure() const
DynamicPrintConfig config = this->full_config();
config.erase("print_host");
config.erase("printhost_apikey");
config.erase("repetier_slug");
config.erase("repetier_group");
config.erase("printhost_cafile");
return config;
}

View File

@ -2002,6 +2002,12 @@ void TabPrinter::build_printhost(ConfigOptionsGroup *optgroup)
option = optgroup->get_option("printhost_apikey");
option.opt.width = Field::def_width_wider();
optgroup->append_single_option_line(option);
option = optgroup->get_option("repetier_slug");
option.opt.width = Field::def_width_wider();
optgroup->append_single_option_line(option);
option = optgroup->get_option("repetier_group");
option.opt.width = Field::def_width_wider();
optgroup->append_single_option_line(option);
const auto ca_file_hint = _utf8(L("HTTPS CA file is optional. It is only needed if you use HTTPS with a self-signed certificate."));
@ -2604,6 +2610,19 @@ void TabPrinter::update_fff()
field->toggle(have_advanced_wipe_volume);
}
}
bool is_repetier = m_config->option<ConfigOptionEnum<PrintHostType>>("host_type")->value == htRepetier;
{
Field *rs = get_field("repetier_slug");
Field *rg = get_field("repetier_group");
if (is_repetier) {
rs->enable();
rg->enable();
} else {
rs->disable();
rg->disable();
}
}
//z step checks
{

View File

@ -16,6 +16,7 @@
#include "Duet.hpp"
#include "FlashAir.hpp"
#include "AstroBox.hpp"
#include "Repetier.hpp"
#include "../GUI/PrintHostDialogs.hpp"
namespace fs = boost::filesystem;
@ -47,6 +48,7 @@ PrintHost* PrintHost::get_print_host(DynamicPrintConfig *config)
case htDuet: return new Duet(config);
case htFlashAir: return new FlashAir(config);
case htAstroBox: return new AstroBox(config);
case htRepetier: return new Repetier(config);
default: return nullptr;
}
} else {

View File

@ -0,0 +1,174 @@
#include "Repetier.hpp"
#include <algorithm>
#include <sstream>
#include <exception>
#include <boost/format.hpp>
#include <boost/log/trivial.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <wx/progdlg.h>
#include "libslic3r/PrintConfig.hpp"
#include "slic3r/GUI/I18N.hpp"
#include "slic3r/GUI/GUI.hpp"
#include "Http.hpp"
namespace fs = boost::filesystem;
namespace pt = boost::property_tree;
namespace Slic3r {
Repetier::Repetier(DynamicPrintConfig *config) :
host(config->opt_string("print_host")),
apikey(config->opt_string("printhost_apikey")),
cafile(config->opt_string("printhost_cafile")),
slug(config->opt_string("repetier_slug")),
group(config->opt_string("repetier_group"))
{}
const char* Repetier::get_name() const { return "Repetier"; }
bool Repetier::test(wxString &msg) const
{
// Since the request is performed synchronously here,
// it is ok to refer to `msg` from within the closure
const char *name = get_name();
bool res = true;
auto url = make_url("printer/info");
BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Get version at: %2%") % name % url;
auto http = Http::get(std::move(url));
set_auth(http);
http.on_error([&](std::string body, std::string error, unsigned status) {
BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Error getting version: %2%, HTTP %3%, body: `%4%`") % name % error % status % body;
res = false;
msg = format_error(body, error, status);
})
.on_complete([&, this](std::string body, unsigned) {
BOOST_LOG_TRIVIAL(debug) << boost::format("%1%: Got version: %2%") % name % body;
try {
std::stringstream ss(body);
pt::ptree ptree;
pt::read_json(ss, ptree);
const auto text = ptree.get_optional<std::string>("name");
res = validate_version_text(text);
if (! res) {
msg = GUI::from_u8((boost::format(_utf8(L("Mismatched type of print host: %s"))) % (text ? *text : "Repetier")).str());
}
}
catch (const std::exception &) {
res = false;
msg = "Could not parse server response";
}
})
.perform_sync();
return res;
}
wxString Repetier::get_test_ok_msg () const
{
return _(L("Connection to Repetier works correctly."));
}
wxString Repetier::get_test_failed_msg (wxString &msg) const
{
return GUI::from_u8((boost::format("%s: %s\n\n%s")
% _utf8(L("Could not connect to Repetier"))
% std::string(msg.ToUTF8())
% _utf8(L("Note: Repetier version at least 0.90.0 is required."))).str());
}
bool Repetier::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const
{
const char *name = get_name();
const auto upload_filename = upload_data.upload_path.filename();
const auto upload_parent_path = upload_data.upload_path.parent_path();
wxString test_msg;
if (! test(test_msg)) {
error_fn(std::move(test_msg));
return false;
}
bool res = true;
auto url = make_url((boost::format("printer/model/%1%") % slug).str());
BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Uploading file %2% at %3%, filename: %4%, path: %5%, print: %6%")
% name
% upload_data.source_path
% url
% upload_filename.string()
% upload_parent_path.string()
% upload_data.start_print;
auto http = Http::post(std::move(url));
set_auth(http);
if (! group.empty()) {
http.form_add("group", group);
}
http.form_add("a", "upload")
.form_add_file("filename", upload_data.source_path.string(), upload_filename.string())
.on_complete([&](std::string body, unsigned status) {
BOOST_LOG_TRIVIAL(debug) << boost::format("%1%: File uploaded: HTTP %2%: %3%") % name % status % body;
})
.on_error([&](std::string body, std::string error, unsigned status) {
BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Error uploading file: %2%, HTTP %3%, body: `%4%`") % name % error % status % body;
error_fn(format_error(body, error, status));
res = false;
})
.on_progress([&](Http::Progress progress, bool &cancel) {
prorgess_fn(std::move(progress), cancel);
if (cancel) {
// Upload was canceled
BOOST_LOG_TRIVIAL(info) << "Repetier: Upload canceled";
res = false;
}
})
.perform_sync();
return res;
}
bool Repetier::validate_version_text(const boost::optional<std::string> &version_text) const
{
return version_text ? boost::starts_with(*version_text, "Repetier") : true;
}
void Repetier::set_auth(Http &http) const
{
http.header("X-Api-Key", apikey);
if (! cafile.empty()) {
http.ca_file(cafile);
}
}
std::string Repetier::make_url(const std::string &path) const
{
if (host.find("http://") == 0 || host.find("https://") == 0) {
if (host.back() == '/') {
return (boost::format("%1%%2%") % host % path).str();
} else {
return (boost::format("%1%/%2%") % host % path).str();
}
} else {
return (boost::format("http://%1%/%2%") % host % path).str();
}
}
}

View File

@ -0,0 +1,49 @@
#ifndef slic3r_Repetier_hpp_
#define slic3r_Repetier_hpp_
#include <string>
#include <wx/string.h>
#include <boost/optional.hpp>
#include "PrintHost.hpp"
namespace Slic3r {
class DynamicPrintConfig;
class Http;
class Repetier : public PrintHost
{
public:
Repetier(DynamicPrintConfig *config);
~Repetier() override = default;
const char* get_name() const;
bool test(wxString &curl_msg) const override;
wxString get_test_ok_msg () const override;
wxString get_test_failed_msg (wxString &msg) const override;
bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const override;
bool has_auto_discovery() const override { return false; }
bool can_test() const override { return true; }
bool can_start_print() const override { return false; }
std::string get_host() const override { return host; }
protected:
virtual bool validate_version_text(const boost::optional<std::string> &version_text) const;
private:
std::string host;
std::string apikey;
std::string cafile;
std::string slug;
std::string group;
void set_auth(Http &http) const;
std::string make_url(const std::string &path) const;
};
}
#endif