mirror of
https://github.com/QIDITECH/QIDIStudio.git
synced 2026-02-07 12:21:50 +03:00
update slic3r
This commit is contained in:
@@ -9,13 +9,21 @@
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "../GUI/MsgDialog.hpp"
|
||||
#include "QDTUtil.hpp"
|
||||
#include "libslic3r/FlushVolCalc.hpp"
|
||||
|
||||
#include "../GUI/DeviceCore/DevConfig.h"
|
||||
#include "../GUI/DeviceCore/DevExtruderSystem.h"
|
||||
#include "../GUI/DeviceCore/DevManager.h"
|
||||
#include "../GUI/DeviceCore/DevStorage.h"
|
||||
#include "libslic3r/FlushVolCalc.hpp"
|
||||
#include "QDTUtil.hpp"
|
||||
#include "../GUI/Plater.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
const float MIN_PA_K_VALUE = 0.0;
|
||||
const float MAX_PA_K_VALUE = 2.0;
|
||||
static const float MIN_PA_K_VALUE_STEP = 0.001;
|
||||
const double MIN_PA_K_VALUE = 0.0;
|
||||
const double MAX_PA_K_VALUE = 2.0;
|
||||
static const double MIN_PA_K_VALUE_STEP = 0.001;
|
||||
|
||||
std::shared_ptr<PrintJob> CalibUtils::print_job;
|
||||
wxString wxstr_temp_dir = fs::path(fs::temp_directory_path() / "calib").wstring();
|
||||
@@ -76,6 +84,16 @@ wxString get_nozzle_volume_type_name(NozzleVolumeType type)
|
||||
return wxString();
|
||||
}
|
||||
|
||||
static int get_physical_extruder_idx(std::vector<int> physical_extruder_maps, int extruder_id)
|
||||
{
|
||||
for (size_t index = 0; index < physical_extruder_maps.size(); ++index) {
|
||||
if (physical_extruder_maps[index] == extruder_id) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return extruder_id;
|
||||
}
|
||||
|
||||
bool is_pa_params_valid(const Calib_Params ¶ms)
|
||||
{
|
||||
if (params.start < MIN_PA_K_VALUE || params.end > MAX_PA_K_VALUE || params.step < MIN_PA_K_VALUE_STEP || params.end < params.start + params.step) {
|
||||
@@ -113,6 +131,8 @@ std::string get_calib_mode_name(CalibMode cali_mode, int stage)
|
||||
switch(cali_mode) {
|
||||
case CalibMode::Calib_PA_Line:
|
||||
return "pa_line_calib_mode";
|
||||
case CalibMode::Calib_Auto_PA_Line:
|
||||
return "auto_pa_line_calib_mode";
|
||||
case CalibMode::Calib_PA_Pattern:
|
||||
return "pa_pattern_calib_mode";
|
||||
case CalibMode::Calib_Flow_Rate:
|
||||
@@ -168,9 +188,9 @@ static bool is_same_nozzle_diameters(const DynamicPrintConfig &full_config, cons
|
||||
for (size_t idx = 0; idx < opt_nozzle_diameters->size(); ++idx)
|
||||
config_nozzle_diameters[idx] = opt_nozzle_diameters->values[idx];
|
||||
|
||||
std::vector<float> machine_nozzle_diameters(obj->m_extder_data.extders.size());
|
||||
for (size_t idx = 0; idx < obj->m_extder_data.extders.size(); ++idx)
|
||||
machine_nozzle_diameters[idx] = obj->m_extder_data.extders[idx].current_nozzle_diameter;
|
||||
std::vector<float> machine_nozzle_diameters(obj->GetExtderSystem()->GetTotalExtderCount());
|
||||
for (size_t idx = 0; idx < obj->GetExtderSystem()->GetTotalExtderCount(); ++idx)
|
||||
machine_nozzle_diameters[idx] = obj->GetExtderSystem()->GetNozzleDiameter(idx);
|
||||
|
||||
if (config_nozzle_diameters.size() != machine_nozzle_diameters.size()) {
|
||||
wxString nozzle_in_preset = wxString::Format(_L("nozzle size in preset: %d"), config_nozzle_diameters.size());
|
||||
@@ -200,7 +220,7 @@ static bool is_same_nozzle_type(const DynamicPrintConfig &full_config, const Mac
|
||||
if (obj == nullptr)
|
||||
return true;
|
||||
|
||||
NozzleType nozzle_type = obj->m_extder_data.extders[0].current_nozzle_type;
|
||||
NozzleType nozzle_type = obj->GetExtderSystem()->GetNozzleType(0);
|
||||
int printer_nozzle_hrc = Print::get_hrc_by_nozzle_type(nozzle_type);
|
||||
|
||||
if (full_config.has("required_nozzle_HRC")) {
|
||||
@@ -208,7 +228,7 @@ static bool is_same_nozzle_type(const DynamicPrintConfig &full_config, const Mac
|
||||
if (abs(filament_nozzle_hrc) > abs(printer_nozzle_hrc)) {
|
||||
BOOST_LOG_TRIVIAL(info) << "filaments hardness mismatch: printer_nozzle_hrc = " << printer_nozzle_hrc << ", filament_nozzle_hrc = " << filament_nozzle_hrc;
|
||||
std::string filament_type = full_config.opt_string("filament_type", 0);
|
||||
error_msg = wxString::Format(_L("Printing %1s material with %2s nozzle may cause nozzle damage."), filament_type, to_wstring_name(NozzleTypeEumnToStr[obj->m_extder_data.extders[0].current_nozzle_type]));
|
||||
error_msg = wxString::Format(_L("Printing %1s material with %2s nozzle may cause nozzle damage."), filament_type, to_wstring_name(NozzleTypeEumnToStr[obj->GetExtderSystem()->GetNozzleType(0)]));
|
||||
error_msg += "\n";
|
||||
|
||||
MessageDialog msg_dlg(nullptr, error_msg, wxEmptyString, wxICON_WARNING | wxOK | wxCANCEL);
|
||||
@@ -244,7 +264,7 @@ static bool check_nozzle_diameter_and_type(const DynamicPrintConfig &full_config
|
||||
return false;
|
||||
|
||||
// P1P/S
|
||||
if (obj->m_extder_data.extders[0].current_nozzle_type == NozzleType::ntUndefine)
|
||||
if (obj->GetExtderSystem()->GetNozzleType(0) == NozzleType::ntUndefine)
|
||||
return true;
|
||||
|
||||
// if (!is_same_nozzle_diameters(full_config, obj, error_msg))
|
||||
@@ -272,6 +292,7 @@ static void init_multi_extruder_params_for_cali(DynamicPrintConfig& config, cons
|
||||
for (size_t index = 0; index < extruder_count; ++index) {
|
||||
if (physical_extruder_maps[index] == extruder_id)
|
||||
{
|
||||
nozzle_volume_types[index] = (int) calib_info.nozzle_volume_type;
|
||||
extruder_id = index + 1;
|
||||
}
|
||||
}
|
||||
@@ -300,6 +321,10 @@ CalibMode CalibUtils::get_calib_mode_by_name(const std::string name, int& cali_s
|
||||
cali_stage = 1;
|
||||
return CalibMode::Calib_PA_Line;
|
||||
}
|
||||
else if (name == "auto_pa_line_calib_mode") {
|
||||
cali_stage = 2;
|
||||
return CalibMode::Calib_PA_Line;
|
||||
}
|
||||
else if (name == "flow_rate_coarse_calib_mode") {
|
||||
cali_stage = 1;
|
||||
return CalibMode::Calib_Flow_Rate;
|
||||
@@ -722,6 +747,7 @@ bool CalibUtils::calib_flowrate(int pass, const CalibInfo &calib_info, wxString
|
||||
full_config.apply(printer_config);
|
||||
|
||||
full_config.set_key_value("filament_ids", new ConfigOptionStrings({calib_info.filament_prest->filament_id}));
|
||||
full_config.set_key_value("enable_wrapping_detection", new ConfigOptionBool(false));
|
||||
|
||||
init_multi_extruder_params_for_cali(full_config, calib_info);
|
||||
|
||||
@@ -805,6 +831,215 @@ void CalibUtils::calib_pa_pattern(const CalibInfo &calib_info, Model& model)
|
||||
model.calib_pa_pattern = std::make_unique<CalibPressureAdvancePattern>(pa_pattern);
|
||||
}
|
||||
|
||||
void CalibUtils::set_for_auto_pa_model_and_config(const std::vector<CalibInfo> &calib_infos, DynamicPrintConfig &full_config, Model &model)
|
||||
{
|
||||
DynamicPrintConfig print_config = calib_infos[0].print_prest->config;
|
||||
|
||||
float nozzle_diameter = full_config.option<ConfigOptionFloatsNullable>("nozzle_diameter")->get_at(0);
|
||||
int extruder_count = full_config.option<ConfigOptionFloatsNullable>("nozzle_diameter")->values.size();
|
||||
|
||||
for (const auto opt : SuggestedConfigCalibPAPattern().float_pairs) { print_config.set_key_value(opt.first, new ConfigOptionFloat(opt.second)); }
|
||||
for (const auto opt : SuggestedConfigCalibPAPattern().floats_pairs) { print_config.set_key_value(opt.first, new ConfigOptionFloatsNullable(opt.second)); }
|
||||
|
||||
std::vector<CalibInfo> sorted_calib_infos = calib_infos;
|
||||
std::sort(sorted_calib_infos.begin(), sorted_calib_infos.end(), [](const CalibInfo &left_item, const CalibInfo &right_item) {
|
||||
return left_item.index < right_item.index;
|
||||
});
|
||||
|
||||
for (const CalibInfo &calib_info : calib_infos) {
|
||||
int index = get_index_for_extruder_parameter(print_config, "outer_wall_speed", calib_info.extruder_id, calib_info.extruder_type, calib_info.nozzle_volume_type);
|
||||
float wall_speed = CalibPressureAdvance::find_optimal_PA_speed(full_config, print_config.get_abs_value("line_width"), print_config.get_abs_value("layer_height"),
|
||||
calib_info.extruder_id, 0);
|
||||
|
||||
ConfigOptionFloatsNullable *wall_speed_speed_opt = print_config.option<ConfigOptionFloatsNullable>("outer_wall_speed");
|
||||
std::vector<double> new_speeds = wall_speed_speed_opt->values;
|
||||
new_speeds[index] = wall_speed;
|
||||
ModelObject* object = model.objects[calib_info.index];
|
||||
object->config.set_key_value("outer_wall_speed", new ConfigOptionFloatsNullable(new_speeds));
|
||||
}
|
||||
|
||||
for (const auto opt : SuggestedConfigCalibPAPattern().nozzle_ratio_pairs) {
|
||||
print_config.set_key_value(opt.first, new ConfigOptionFloat(nozzle_diameter * opt.second / 100));
|
||||
}
|
||||
|
||||
for (const auto opt : SuggestedConfigCalibPAPattern().int_pairs) { print_config.set_key_value(opt.first, new ConfigOptionInt(opt.second)); }
|
||||
|
||||
print_config.set_key_value(SuggestedConfigCalibPAPattern().brim_pair.first, new ConfigOptionEnum<BrimType>(SuggestedConfigCalibPAPattern().brim_pair.second));
|
||||
|
||||
auto* _wall_generator = print_config.option<ConfigOptionEnum<PerimeterGeneratorType>>("wall_generator");
|
||||
_wall_generator->value = PerimeterGeneratorType::Arachne;
|
||||
|
||||
print_config.option<ConfigOptionBool>("enable_prime_tower")->value = false;
|
||||
|
||||
auto get_new_filament_id = [&sorted_calib_infos](int index) -> int {
|
||||
for (size_t i = 0; i < sorted_calib_infos.size(); ++i) {
|
||||
if (index == sorted_calib_infos[i].index) {
|
||||
return (int) (i + 1); // 1 base filament_id
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
// set printable and reset filament_id
|
||||
for (size_t i = 0; i < model.objects.size(); ++i) {
|
||||
auto iter = std::find_if(calib_infos.begin(), calib_infos.end(), [i](const CalibInfo &item) { return item.index == i; });
|
||||
|
||||
if (iter == calib_infos.end()) {
|
||||
model.objects[i]->printable = false;
|
||||
} else {
|
||||
ModelObject *object = model.objects[i];
|
||||
object->config.set_key_value("extruder", new ConfigOptionInt(get_new_filament_id(iter->index)));
|
||||
for (auto *volume : object->volumes) {
|
||||
if (volume->config.has("extruder")) volume->config.erase("extruder");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DynamicPrintConfig full_config;
|
||||
full_config.apply(print_config);
|
||||
full_config.option<ConfigOptionEnum<FilamentMapMode>>("filament_map_mode", true)->value = FilamentMapMode::fmmManual;
|
||||
|
||||
// nozzle volume type
|
||||
std::vector<int>& nozzle_volume_types = full_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type", true)->values;
|
||||
nozzle_volume_types.resize(extruder_count, NozzleVolumeType::nvtStandard);
|
||||
auto nozzle_flush_dataset = full_config.option<ConfigOptionIntsNullable>("nozzle_flush_dataset", true)->values;
|
||||
nozzle_flush_dataset.resize(extruder_count, 0);
|
||||
|
||||
int filament_nums = calib_infos.size();
|
||||
std::vector<int> physical_extruder_maps = dynamic_cast<ConfigOptionInts *>(full_config.option("physical_extruder_map", true))->values;
|
||||
for (size_t filament_index = 0; filament_index < calib_infos.size(); ++filament_index) {
|
||||
CalibInfo calib_info = calib_infos[filament_index];
|
||||
int extruder_id = calib_info.extruder_id;
|
||||
for (size_t index = 0; index < extruder_count; ++index) {
|
||||
if (physical_extruder_maps[index] == extruder_id) {
|
||||
extruder_id = index;
|
||||
}
|
||||
}
|
||||
nozzle_volume_types[extruder_id] = (int)calib_info.nozzle_volume_type;
|
||||
}
|
||||
|
||||
// filament map transform to 1 base
|
||||
std::vector<int> &filament_maps = full_config.option<ConfigOptionInts>("filament_map", true)->values;
|
||||
std::transform(filament_maps.begin(), filament_maps.end(), filament_maps.begin(), [](int value) { return value + 1; });
|
||||
|
||||
std::vector<std::string> &filament_colors = full_config.option<ConfigOptionStrings>("filament_colour")->values;
|
||||
filament_colors.resize(sorted_calib_infos.size(), "#000000");
|
||||
for (size_t i = 0; i < sorted_calib_infos.size(); ++i) {
|
||||
filament_colors[i] = sorted_calib_infos[i].filament_color;
|
||||
}
|
||||
|
||||
// Add flush volume matrix
|
||||
std::vector<double> flush_matrix_vec;
|
||||
for (int e_idx = 0; e_idx < extruder_count; ++e_idx) {
|
||||
const std::vector<int> &min_flush_volumes = get_min_flush_volumes(full_config, e_idx);
|
||||
for (size_t from_idx = 0; from_idx < filament_nums; ++from_idx) {
|
||||
for (size_t to_idx = 0; to_idx < filament_nums; ++to_idx) {
|
||||
if (from_idx == to_idx) {
|
||||
flush_matrix_vec.emplace_back(0);
|
||||
}
|
||||
else {
|
||||
Slic3r::FlushVolCalculator calculator(min_flush_volumes[from_idx], Slic3r::g_max_flush_volume, nozzle_flush_dataset[e_idx]);
|
||||
wxColour from = wxColour(filament_colors[from_idx]);
|
||||
wxColour to = wxColour(filament_colors[to_idx]);
|
||||
int volume = calculator.calc_flush_vol(from.Alpha(), from.Red(), from.Green(), from.Blue(), to.Alpha(), to.Red(), to.Green(), to.Blue());
|
||||
flush_matrix_vec.emplace_back(double(volume));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
std::vector<double> &config_matrix = full_config.option<ConfigOptionFloats>("flush_volumes_matrix")->values;
|
||||
set_flush_volumes_matrix(config_matrix, flush_matrix_vec, -1, extruder_count);
|
||||
}
|
||||
|
||||
bool CalibUtils::calib_generic_auto_pa_cali(const std::vector<CalibInfo> &calib_infos, wxString &error_message)
|
||||
{
|
||||
DeviceManager *dev = Slic3r::GUI::wxGetApp().getDeviceManager();
|
||||
if (!dev) {
|
||||
error_message = _L("Need select printer");
|
||||
return false;
|
||||
}
|
||||
|
||||
MachineObject *obj_ = dev->get_selected_machine();
|
||||
if (obj_ == nullptr) {
|
||||
error_message = _L("Need select printer");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!check_printable_status_before_cali(obj_, calib_infos, error_message))
|
||||
return false;
|
||||
|
||||
const Calib_Params ¶ms = calib_infos[0].params;
|
||||
if (params.mode != CalibMode::Calib_Auto_PA_Line)
|
||||
return false;
|
||||
|
||||
Model model;
|
||||
std::string input_file;
|
||||
if (obj_->is_multi_extruders())
|
||||
input_file = Slic3r::resources_dir() + "/calib/pressure_advance/auto_pa_line_dual.3mf";
|
||||
else
|
||||
input_file = Slic3r::resources_dir() + "/calib/pressure_advance/auto_pa_line_single.3mf";
|
||||
|
||||
read_model_from_file(input_file, model);
|
||||
|
||||
DynamicPrintConfig print_config = calib_infos[0].print_prest->config;
|
||||
DynamicPrintConfig filament_config = calib_infos[0].filament_prest->config;
|
||||
DynamicPrintConfig printer_config = calib_infos[0].printer_prest->config;
|
||||
|
||||
Preset printer_preset = *calib_infos[0].printer_prest;
|
||||
Preset print_preset = *calib_infos[0].print_prest;
|
||||
std::vector<Preset> filament_presets;
|
||||
std::vector<int> filament_map;
|
||||
filament_map.resize(calib_infos.size());
|
||||
std::vector<int> physical_extruder_maps = dynamic_cast<ConfigOptionInts *>(printer_config.option("physical_extruder_map", true))->values;
|
||||
for (size_t i = 0; i < calib_infos.size(); ++i) {
|
||||
CalibInfo calib_info = calib_infos[i];
|
||||
calib_info.filament_prest->config.set_key_value("curr_bed_type", new ConfigOptionEnum<BedType>(calib_info.bed_type));
|
||||
filament_presets.emplace_back(*calib_info.filament_prest);
|
||||
for (size_t index = 0; index < physical_extruder_maps.size(); ++index) {
|
||||
if (physical_extruder_maps[index] == calib_info.extruder_id) {
|
||||
filament_map[i] = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PresetBundle *preset_bundle = wxGetApp().preset_bundle;
|
||||
DynamicPrintConfig full_config = PresetBundle::construct_full_config(printer_preset, print_preset, preset_bundle->project_config, filament_presets, false, filament_map);
|
||||
|
||||
set_for_auto_pa_model_and_config(calib_infos, full_config, model);
|
||||
if (!process_and_store_3mf(&model, full_config, params, error_message))
|
||||
return false;
|
||||
|
||||
try {
|
||||
json js;
|
||||
if (params.mode == CalibMode::Calib_PA_Line)
|
||||
js["cali_type"] = "cali_pa_line";
|
||||
else if (params.mode == CalibMode::Calib_PA_Pattern)
|
||||
js["cali_type"] = "cali_pa_pattern";
|
||||
else if (params.mode == CalibMode::Calib_Auto_PA_Line)
|
||||
js["cali_type"] = "cali_auto_pa_line";
|
||||
|
||||
const ConfigOptionFloatsNullable *nozzle_diameter_config = printer_config.option<ConfigOptionFloatsNullable>("nozzle_diameter");
|
||||
assert(nozzle_diameter_config->values.size() > 0);
|
||||
float nozzle_diameter = nozzle_diameter_config->values[0];
|
||||
|
||||
js["nozzle_diameter"] = nozzle_diameter;
|
||||
std::string filament_ids;
|
||||
for (const auto calib_info : calib_infos) {
|
||||
filament_ids += calib_info.filament_prest->filament_id;
|
||||
filament_ids += " ";
|
||||
}
|
||||
js["filament_id"] = filament_ids;
|
||||
js["printer_type"] = obj_->printer_type;
|
||||
NetworkAgent *agent = GUI::wxGetApp().getAgent();
|
||||
if (agent)
|
||||
agent->track_event("cali", js.dump());
|
||||
} catch (...) {}
|
||||
|
||||
send_to_print(calib_infos, error_message);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CalibUtils::calib_generic_PA(const CalibInfo &calib_info, wxString &error_message)
|
||||
{
|
||||
DeviceManager *dev = Slic3r::GUI::wxGetApp().getDeviceManager();
|
||||
@@ -850,6 +1085,9 @@ bool CalibUtils::calib_generic_PA(const CalibInfo &calib_info, wxString &error_m
|
||||
full_config.apply(filament_config);
|
||||
full_config.apply(printer_config);
|
||||
|
||||
full_config.set_key_value("filament_ids", new ConfigOptionStrings({calib_info.filament_prest->filament_id}));
|
||||
full_config.set_key_value("enable_wrapping_detection", new ConfigOptionBool(false));
|
||||
|
||||
init_multi_extruder_params_for_cali(full_config, calib_info);
|
||||
|
||||
if (!process_and_store_3mf(&model, full_config, params, error_message))
|
||||
@@ -1184,40 +1422,37 @@ bool CalibUtils::check_printable_status_before_cali(const MachineObject *obj, co
|
||||
return false;
|
||||
}
|
||||
|
||||
float cali_diameter = cali_infos.calib_datas[0].nozzle_diameter;
|
||||
int extruder_id = cali_infos.calib_datas[0].extruder_id;
|
||||
for (const auto& cali_info : cali_infos.calib_datas) {
|
||||
if (cali_infos.cali_mode == CalibMode::Calib_PA_Line && !is_support_auto_pa_cali(cali_info.filament_id)) {
|
||||
error_message = _L("TPU 90A/TPU 85A is too soft and does not support automatic Flow Dynamics calibration.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_approx(cali_diameter, cali_info.nozzle_diameter)) {
|
||||
error_message = _L("Automatic calibration only supports cases where the left and right nozzle diameters are identical.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (extruder_id >= obj->m_extder_data.extders.size()) {
|
||||
error_message = _L("The number of printer extruders and the printer selected for calibration does not match.");
|
||||
return false;
|
||||
}
|
||||
|
||||
float diameter = obj->m_extder_data.extders[extruder_id].current_nozzle_diameter;
|
||||
bool is_multi_extruder = obj->is_multi_extruders();
|
||||
std::vector<NozzleFlowType> nozzle_volume_types;
|
||||
if (is_multi_extruder) {
|
||||
for (const Extder& extruder : obj->m_extder_data.extders) {
|
||||
nozzle_volume_types.emplace_back(extruder.current_nozzle_flow_type);
|
||||
for (const DevExtder& extruder : obj->GetExtderSystem()->GetExtruders()) {
|
||||
nozzle_volume_types.emplace_back(extruder.GetNozzleFlowType());
|
||||
}
|
||||
}
|
||||
|
||||
Preset *printer_preset = get_printer_preset(obj);
|
||||
|
||||
for (const auto &cali_info : cali_infos.calib_datas) {
|
||||
wxString name = _L("left");
|
||||
if (cali_info.extruder_id == 0) {
|
||||
name = _L("right");
|
||||
}
|
||||
|
||||
float cali_diameter = cali_info.nozzle_diameter;
|
||||
int extruder_id = cali_info.extruder_id;
|
||||
if (extruder_id >= obj->GetExtderSystem()->GetTotalExtderSize()) {
|
||||
error_message = _L("The number of printer extruders and the printer selected for calibration does not match.");
|
||||
return false;
|
||||
}
|
||||
|
||||
float diameter = obj->GetExtderSystem()->GetNozzleDiameter(extruder_id);
|
||||
if (!is_approx(cali_info.nozzle_diameter, diameter)) {
|
||||
if (is_multi_extruder)
|
||||
error_message = wxString::Format(_L("The currently selected nozzle diameter of %s extruder does not match the actual nozzle diameter.\n"
|
||||
@@ -1245,6 +1480,74 @@ bool CalibUtils::check_printable_status_before_cali(const MachineObject *obj, co
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CalibUtils::check_printable_status_before_cali(const MachineObject *obj, const std::vector<CalibInfo> &cali_infos, wxString &error_message)
|
||||
{
|
||||
if (!obj) {
|
||||
error_message = _L("Need select printer");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cali_infos.empty())
|
||||
return true;
|
||||
|
||||
float cali_diameter = cali_infos[0].nozzle_diameter;
|
||||
int extruder_id = cali_infos[0].extruder_id;
|
||||
for (const auto &cali_info : cali_infos) {
|
||||
if (cali_infos[0].params.mode == CalibMode::Calib_Auto_PA_Line && !is_support_auto_pa_cali(cali_info.filament_prest->filament_id)) {
|
||||
error_message = _L("TPU 90A/TPU 85A is too soft and does not support automatic Flow Dynamics calibration.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_approx(cali_diameter, cali_info.nozzle_diameter)) {
|
||||
error_message = _L("Automatic calibration only supports cases where the left and right nozzle diameters are identical.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (extruder_id >= obj->GetExtderSystem()->GetExtruders().size()) {
|
||||
error_message = _L("The number of printer extruders and the printer selected for calibration does not match.");
|
||||
return false;
|
||||
}
|
||||
|
||||
float diameter = obj->GetExtderSystem()->GetNozzleDiameter(extruder_id);
|
||||
bool is_multi_extruder = obj->is_multi_extruders();
|
||||
std::vector<NozzleFlowType> nozzle_volume_types;
|
||||
if (is_multi_extruder) {
|
||||
for (auto &extruder : obj->GetExtderSystem()->GetExtruders()) { nozzle_volume_types.emplace_back(extruder.GetNozzleFlowType()); }
|
||||
}
|
||||
|
||||
for (const auto &cali_info : cali_infos) {
|
||||
wxString name = _L("left");
|
||||
if (cali_info.extruder_id == 0) { name = _L("right"); }
|
||||
|
||||
if (!is_approx(cali_info.nozzle_diameter, diameter)) {
|
||||
if (is_multi_extruder)
|
||||
error_message = wxString::Format(_L("The currently selected nozzle diameter of %s extruder does not match the actual nozzle diameter.\n"
|
||||
"Please click the Sync button above and restart the calibration."),
|
||||
name);
|
||||
else
|
||||
error_message = _L("The nozzle diameter does not match the actual printer nozzle diameter.\n"
|
||||
"Please click the Sync button above and restart the calibration.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_multi_extruder) {
|
||||
if (nozzle_volume_types[cali_info.extruder_id] == NozzleFlowType::NONE_FLOWTYPE) {
|
||||
error_message = wxString::Format(_L("Printer %s nozzle information has not been set. Please configure it before proceeding with the calibration."), name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NozzleVolumeType(nozzle_volume_types[cali_info.extruder_id] - 1) != cali_info.nozzle_volume_type) {
|
||||
error_message = wxString::Format(_L("The currently selected nozzle type of %s extruder does not match the actual printer nozzle type.\n"
|
||||
"Please click the Sync button above and restart the calibration."),
|
||||
name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CalibUtils::check_printable_status_before_cali(const MachineObject* obj, const CalibInfo& cali_info, wxString& error_message)
|
||||
{
|
||||
if (!obj) {
|
||||
@@ -1255,12 +1558,12 @@ bool CalibUtils::check_printable_status_before_cali(const MachineObject* obj, co
|
||||
const ConfigOptionFloatsNullable *nozzle_diameter_config = cali_info.printer_prest->config.option<ConfigOptionFloatsNullable>("nozzle_diameter");
|
||||
float nozzle_diameter = nozzle_diameter_config->values[0];
|
||||
|
||||
float diameter = obj->m_extder_data.extders[cali_info.extruder_id].current_nozzle_diameter;
|
||||
float diameter = obj->GetExtderSystem()->GetNozzleDiameter(cali_info.extruder_id);
|
||||
bool is_multi_extruder = obj->is_multi_extruders();
|
||||
std::vector<NozzleFlowType> nozzle_volume_types;
|
||||
if (is_multi_extruder) {
|
||||
for (const Extder& extruder : obj->m_extder_data.extders) {
|
||||
nozzle_volume_types.emplace_back(extruder.current_nozzle_flow_type);
|
||||
for (const DevExtder& extruder : obj->GetExtderSystem()->GetExtruders()) {
|
||||
nozzle_volume_types.emplace_back(extruder.GetNozzleFlowType());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1348,7 +1651,7 @@ bool CalibUtils::process_and_store_3mf(Model *model, const DynamicPrintConfig &f
|
||||
|
||||
BuildVolume build_volume(bedfs, print_height, extruder_areas, extruder_heights);
|
||||
unsigned int count = model->update_print_volume_state(build_volume);
|
||||
if (count == 0) {
|
||||
if (count == 0 && params.mode != CalibMode::Calib_Auto_PA_Line) {
|
||||
error_message = _L("Unable to calibrate: maybe because the set calibration value range is too large, or the step is too small");
|
||||
return false;
|
||||
}
|
||||
@@ -1511,19 +1814,19 @@ void CalibUtils::send_to_print(const CalibInfo &calib_info, wxString &error_mess
|
||||
return;
|
||||
}
|
||||
|
||||
else if (!obj_->is_support_print_without_sd && (obj_->get_sdcard_state() == MachineObject::SdcardState::NO_SDCARD)) {
|
||||
else if (!obj_->GetConfig()->SupportPrintWithoutSD() && (obj_->GetStorage()->get_sdcard_state() == DevStorage::SdcardState::NO_SDCARD)) {
|
||||
error_message = _L("Storage needs to be inserted before printing.");
|
||||
return;
|
||||
}
|
||||
if (obj_->is_lan_mode_printer()) {
|
||||
if (obj_->get_sdcard_state() == MachineObject::SdcardState::NO_SDCARD) {
|
||||
if (obj_->GetStorage()->get_sdcard_state() == DevStorage::SdcardState::NO_SDCARD) {
|
||||
error_message = _L("Storage needs to be inserted before printing via LAN.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
print_job = std::make_shared<PrintJob>(std::move(process_bar), wxGetApp().plater(), dev_id);
|
||||
print_job->m_dev_ip = obj_->dev_ip;
|
||||
print_job->m_dev_ip = obj_->get_dev_ip();
|
||||
print_job->m_ftp_folder = obj_->get_ftp_folder();
|
||||
print_job->m_access_code = obj_->get_access_code();
|
||||
|
||||
@@ -1556,9 +1859,9 @@ void CalibUtils::send_to_print(const CalibInfo &calib_info, wxString &error_mess
|
||||
print_job->plate_data = plate_data;
|
||||
print_job->m_print_type = "from_normal";
|
||||
|
||||
print_job->task_ams_mapping = select_ams;
|
||||
print_job->task_ams_mapping = "[" + select_ams + "]";
|
||||
print_job->task_ams_mapping_info = "";
|
||||
print_job->task_use_ams = select_ams == "[254]" ? false : true;
|
||||
print_job->task_use_ams = !devPrinterUtil::IsVirtualSlot(select_ams);
|
||||
|
||||
std::string new_ams_mapping = "[{\"ams_id\":" + std::to_string(calib_info.ams_id) + ", \"slot_id\":" + std::to_string(calib_info.slot_id) + "}]";
|
||||
print_job->task_ams_mapping2 = new_ams_mapping;
|
||||
@@ -1567,8 +1870,8 @@ void CalibUtils::send_to_print(const CalibInfo &calib_info, wxString &error_mess
|
||||
print_job->m_project_name = get_calib_mode_name(cali_mode, flow_ratio_mode);
|
||||
print_job->set_calibration_task(true);
|
||||
|
||||
print_job->has_sdcard = obj_->get_sdcard_state() == MachineObject::SdcardState::HAS_SDCARD_NORMAL;
|
||||
print_job->set_print_config(MachineBedTypeString[bed_type], true, false, false, false, true, false, 0, 0, 0);
|
||||
print_job->has_sdcard = obj_->GetStorage()->get_sdcard_state() == DevStorage::HAS_SDCARD_NORMAL;
|
||||
print_job->set_print_config(MachineBedTypeString[bed_type], true, false, false, false, true, false, 0, 0, 0, 0);
|
||||
print_job->set_print_job_finished_event(wxGetApp().plater()->get_send_calibration_finished_event(), print_job->m_project_name);
|
||||
|
||||
{ // after send: record the print job
|
||||
@@ -1581,6 +1884,123 @@ void CalibUtils::send_to_print(const CalibInfo &calib_info, wxString &error_mess
|
||||
print_job->start();
|
||||
}
|
||||
|
||||
void CalibUtils::send_to_print(const std::vector<CalibInfo> &calib_infos, wxString &error_message, int flow_ratio_mode)
|
||||
{
|
||||
std::string dev_id = calib_infos[0].dev_id;
|
||||
std::shared_ptr<ProgressIndicator> process_bar = calib_infos[0].process_bar;
|
||||
BedType bed_type = calib_infos[0].bed_type;
|
||||
|
||||
DeviceManager *dev = Slic3r::GUI::wxGetApp().getDeviceManager();
|
||||
if (!dev) {
|
||||
error_message = _L("Need select printer");
|
||||
return;
|
||||
}
|
||||
|
||||
MachineObject *obj_ = dev->get_selected_machine();
|
||||
if (obj_ == nullptr) {
|
||||
error_message = _L("Need select printer");
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj_->is_in_upgrading()) {
|
||||
error_message = _L("Cannot send the print job when the printer is updating firmware");
|
||||
return;
|
||||
} else if (obj_->is_system_printing()) {
|
||||
error_message = _L("The printer is executing instructions. Please restart printing after it ends");
|
||||
return;
|
||||
} else if (obj_->is_in_printing()) {
|
||||
error_message = _L("The printer is busy on other print job");
|
||||
return;
|
||||
}
|
||||
|
||||
else if (!obj_->GetConfig()->SupportPrintWithoutSD() && (obj_->GetStorage()->get_sdcard_state() == DevStorage::SdcardState::NO_SDCARD)) {
|
||||
error_message = _L("Storage needs to be inserted before printing.");
|
||||
return;
|
||||
}
|
||||
if (obj_->is_lan_mode_printer()) {
|
||||
if (obj_->GetStorage()->get_sdcard_state() == DevStorage::SdcardState::NO_SDCARD) {
|
||||
error_message = _L("Storage needs to be inserted before printing via LAN.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
print_job = std::make_shared<PrintJob>(std::move(process_bar), wxGetApp().plater(), dev_id);
|
||||
print_job->m_dev_ip = obj_->get_dev_ip();
|
||||
print_job->m_ftp_folder = obj_->get_ftp_folder();
|
||||
print_job->m_access_code = obj_->get_access_code();
|
||||
|
||||
#if !QDT_RELEASE_TO_PUBLIC
|
||||
print_job->m_local_use_ssl_for_ftp = wxGetApp().app_config->get("enable_ssl_for_ftp") == "true" ? true : false;
|
||||
print_job->m_local_use_ssl_for_mqtt = wxGetApp().app_config->get("enable_ssl_for_mqtt") == "true" ? true : false;
|
||||
#else
|
||||
print_job->m_local_use_ssl_for_ftp = obj_->local_use_ssl_for_ftp;
|
||||
print_job->m_local_use_ssl_for_mqtt = obj_->local_use_ssl_for_mqtt;
|
||||
#endif
|
||||
|
||||
print_job->connection_type = obj_->connection_type();
|
||||
print_job->cloud_print_only = obj_->is_support_cloud_print_only;
|
||||
|
||||
PrintPrepareData job_data;
|
||||
job_data.is_from_plater = false;
|
||||
job_data.plate_idx = 0;
|
||||
job_data._3mf_config_path = config_3mf_path;
|
||||
job_data._3mf_path = path;
|
||||
job_data._temp_path = temp_dir;
|
||||
|
||||
PlateListData plate_data;
|
||||
plate_data.is_valid = true;
|
||||
plate_data.plate_count = 1;
|
||||
plate_data.cur_plate_index = 0;
|
||||
plate_data.bed_type = bed_type;
|
||||
|
||||
print_job->job_data = job_data;
|
||||
print_job->plate_data = plate_data;
|
||||
print_job->m_print_type = "from_normal";
|
||||
|
||||
// set AMS mapping
|
||||
std::string select_ams = "[";
|
||||
std::string new_select_ams = "[";
|
||||
for (size_t i = 0; i < calib_infos.size(); ++i) {
|
||||
select_ams += calib_infos[i].select_ams;
|
||||
new_select_ams += "{\"ams_id\":" + std::to_string(calib_infos[i].ams_id) + ", \"slot_id\":" + std::to_string(calib_infos[i].slot_id) + "}";
|
||||
if (i != calib_infos.size() - 1) {
|
||||
select_ams += ",";
|
||||
new_select_ams += ",";
|
||||
}
|
||||
}
|
||||
select_ams += "]";
|
||||
new_select_ams += "]";
|
||||
print_job->task_ams_mapping = select_ams;
|
||||
print_job->task_ams_mapping_info = "";
|
||||
print_job->task_ams_mapping2 = new_select_ams;
|
||||
|
||||
print_job->task_use_ams = false;
|
||||
for (const CalibInfo& calib_info : calib_infos) {
|
||||
if (calib_info.select_ams != VIRTUAL_AMS_MAIN_ID_STR && calib_info.select_ams != VIRTUAL_AMS_DEPUTY_ID_STR) {
|
||||
print_job->task_use_ams = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CalibMode cali_mode = calib_infos[0].params.mode;
|
||||
print_job->m_project_name = get_calib_mode_name(cali_mode, flow_ratio_mode);
|
||||
print_job->set_calibration_task(true);
|
||||
|
||||
print_job->has_sdcard = obj_->GetStorage()->get_sdcard_state() == DevStorage::HAS_SDCARD_NORMAL;
|
||||
print_job->set_print_config(MachineBedTypeString[bed_type], true, true, false, false, true, false, 0, 1, 0, 0);
|
||||
print_job->set_print_job_finished_event(wxGetApp().plater()->get_send_calibration_finished_event(), print_job->m_project_name);
|
||||
|
||||
{ // after send: record the print job
|
||||
json j;
|
||||
j["print"]["ams_mapping"] = print_job->task_ams_mapping;
|
||||
j["print"]["ams_mapping_2"] = print_job->task_ams_mapping2;
|
||||
j["print"]["project_name"] = print_job->m_project_name;
|
||||
j["print"]["is_cali_task"] = print_job->m_is_calibration_task;
|
||||
BOOST_LOG_TRIVIAL(info) << "send_cali_job - after send: " << j.dump();
|
||||
}
|
||||
|
||||
print_job->start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,15 +9,17 @@ class ProgressIndicator;
|
||||
class Preset;
|
||||
|
||||
namespace GUI {
|
||||
extern const float MIN_PA_K_VALUE;
|
||||
extern const float MAX_PA_K_VALUE;
|
||||
extern const double MIN_PA_K_VALUE;
|
||||
extern const double MAX_PA_K_VALUE;
|
||||
|
||||
class CalibInfo
|
||||
{
|
||||
public:
|
||||
int index = -1;
|
||||
int extruder_id = 0;
|
||||
int ams_id = 0;
|
||||
int slot_id = 0;
|
||||
float nozzle_diameter;
|
||||
ExtruderType extruder_type{ExtruderType::etDirectDrive};
|
||||
NozzleVolumeType nozzle_volume_type;
|
||||
Calib_Params params;
|
||||
@@ -25,6 +27,7 @@ public:
|
||||
Preset* filament_prest;
|
||||
Preset* print_prest;
|
||||
BedType bed_type;
|
||||
std::string filament_color;
|
||||
std::string dev_id;
|
||||
std::string select_ams;
|
||||
std::shared_ptr<ProgressIndicator> process_bar;
|
||||
@@ -60,6 +63,9 @@ public:
|
||||
|
||||
static void calib_pa_pattern(const CalibInfo &calib_info, Model &model);
|
||||
|
||||
static void set_for_auto_pa_model_and_config(const std::vector<CalibInfo> &calib_info, DynamicPrintConfig &full_config, Model &model);
|
||||
|
||||
static bool calib_generic_auto_pa_cali(const std::vector<CalibInfo> &calib_info, wxString & error_message);
|
||||
static bool calib_generic_PA(const CalibInfo &calib_info, wxString &error_message);
|
||||
static void calib_temptue(const CalibInfo &calib_info, wxString &error_message);
|
||||
static void calib_max_vol_speed(const CalibInfo &calib_info, wxString &error_message);
|
||||
@@ -78,10 +84,12 @@ public:
|
||||
|
||||
static bool check_printable_status_before_cali(const MachineObject *obj, const X1CCalibInfos &cali_infos, wxString &error_message);
|
||||
static bool check_printable_status_before_cali(const MachineObject *obj, const CalibInfo &cali_info, wxString &error_message);
|
||||
static bool check_printable_status_before_cali(const MachineObject *obj, const std::vector<CalibInfo> &cali_infos, wxString &error_message);
|
||||
|
||||
private:
|
||||
static bool process_and_store_3mf(Model* model, const DynamicPrintConfig& full_config, const Calib_Params& params, wxString& error_message);
|
||||
static void send_to_print(const CalibInfo &calib_info, wxString& error_message, int flow_ratio_mode = 0); // 0: none 1: coarse 2: fine
|
||||
static void send_to_print(const std::vector<CalibInfo> &calib_infos, wxString &error_message, int flow_ratio_mode = 0); // 0: none 1: coarse 2: fine
|
||||
};
|
||||
|
||||
extern void get_tray_ams_and_slot_id(MachineObject* obj, int in_tray_id, int &ams_id, int &slot_id, int &tray_id);
|
||||
|
||||
821
src/slic3r/Utils/HelioDragon.cpp
Normal file
821
src/slic3r/Utils/HelioDragon.cpp
Normal file
@@ -0,0 +1,821 @@
|
||||
#include "HelioDragon.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <wx/string.h>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/asio/ip/address.hpp>
|
||||
|
||||
#include "PrintHost.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "libslic3r/PrintBase.hpp"
|
||||
#include "libslic3r/Print.hpp"
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include "../GUI/PartPlate.hpp"
|
||||
#include "../GUI/GUI_App.hpp"
|
||||
#include "../GUI/Event.hpp"
|
||||
#include "../GUI/Plater.hpp"
|
||||
#include "../GUI/NotificationManager.hpp"
|
||||
#include "wx/app.h"
|
||||
#include "cstdio"
|
||||
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
std::vector<HelioQuery::SupportedData> HelioQuery::global_supported_printers;
|
||||
std::vector<HelioQuery::SupportedData> HelioQuery::global_supported_materials;
|
||||
|
||||
void HelioQuery::request_support_machine(const std::string helio_api_url, const std::string helio_api_key, int page)
|
||||
{
|
||||
std::string query_body = R"( {
|
||||
"query": "query GetPrinters($page: Int) { printers(page: $page, pageSize: 20) { pages pageInfo { hasNextPage } objects { ... on Printer { id name alternativeNames { qidistudio } } } } }",
|
||||
"variables": {"page": %1%}
|
||||
} )";
|
||||
|
||||
query_body = boost::str(boost::format(query_body) % page);
|
||||
|
||||
std::string url_copy = helio_api_url;
|
||||
std::string key_copy = helio_api_key;
|
||||
int page_copy = page;
|
||||
|
||||
auto http = Http::post(url_copy);
|
||||
|
||||
http.header("Content-Type", "application/json").header("Authorization", "Bearer " + helio_api_key).set_post_body(query_body);
|
||||
|
||||
http.timeout_connect(20)
|
||||
.timeout_max(100)
|
||||
.on_complete([url_copy, key_copy, page_copy](std::string body, unsigned status) {
|
||||
BOOST_LOG_TRIVIAL(info) << "request_support_machine" << body;
|
||||
try {
|
||||
nlohmann::json parsed_obj = nlohmann::json::parse(body);
|
||||
std::vector<HelioQuery::SupportedData> supported_printers;
|
||||
if (parsed_obj.contains("data") && parsed_obj["data"].contains("printers")) {
|
||||
auto materials = parsed_obj["data"]["printers"];
|
||||
if (materials.contains("objects") && materials["objects"].is_array()) {
|
||||
for (const auto &pobj : materials["objects"]) {
|
||||
HelioQuery::SupportedData sp;
|
||||
if (pobj.contains("id") && !pobj["id"].is_null()) { sp.id = pobj["id"].get<std::string>(); }
|
||||
if (pobj.contains("name") && !pobj["id"].is_null()) { sp.name = pobj["name"].get<std::string>(); }
|
||||
|
||||
if (pobj.contains("alternativeNames") && pobj["alternativeNames"].is_object()) {
|
||||
auto alternativeNames = pobj["alternativeNames"];
|
||||
|
||||
if (alternativeNames.contains("qidistudio") && !alternativeNames["qidistudio"].is_null()) {
|
||||
sp.native_name = alternativeNames["qidistudio"].get<std::string>();
|
||||
}
|
||||
}
|
||||
|
||||
supported_printers.push_back(sp);
|
||||
}
|
||||
}
|
||||
|
||||
HelioQuery::global_supported_printers.insert(HelioQuery::global_supported_printers.end(), supported_printers.begin(), supported_printers.end());
|
||||
|
||||
if (materials.contains("pageInfo") && materials["pageInfo"].contains("hasNextPage") && materials["pageInfo"]["hasNextPage"].get<bool>()) {
|
||||
HelioQuery::request_support_machine(url_copy, key_copy, page_copy + 1);
|
||||
}
|
||||
}
|
||||
} catch (...) {}
|
||||
})
|
||||
.on_error([](std::string body, std::string error, unsigned status) {
|
||||
// BOOST_LOG_TRIVIAL(info) << (boost::format("error: %1%, message: %2%") % error % body).str()
|
||||
})
|
||||
.perform();
|
||||
}
|
||||
|
||||
void HelioQuery::request_support_material(const std::string helio_api_url, const std::string helio_api_key, int page)
|
||||
{
|
||||
std::string query_body = R"( {
|
||||
"query": "query GetMaterias($page: Int) { materials(page: $page, pageSize: 20) { pages pageInfo { hasNextPage } objects { ... on Material { id name alternativeNames { qidistudio } } } } }",
|
||||
"variables": {"page": %1%}
|
||||
} )";
|
||||
|
||||
query_body = boost::str(boost::format(query_body) % page);
|
||||
|
||||
std::string url_copy = helio_api_url;
|
||||
std::string key_copy = helio_api_key;
|
||||
int page_copy = page;
|
||||
|
||||
auto http = Http::post(url_copy);
|
||||
|
||||
http.header("Content-Type", "application/json").header("Authorization", "Bearer " + helio_api_key).set_post_body(query_body);
|
||||
|
||||
http.timeout_connect(20)
|
||||
.timeout_max(100)
|
||||
.on_complete([url_copy, key_copy, page_copy](std::string body, unsigned status) {
|
||||
BOOST_LOG_TRIVIAL(info) << "request_support_material" << body;
|
||||
try {
|
||||
nlohmann::json parsed_obj = nlohmann::json::parse(body);
|
||||
std::vector<HelioQuery::SupportedData> supported_materials;
|
||||
|
||||
if (parsed_obj.contains("data") && parsed_obj["data"].contains("materials")) {
|
||||
auto materials = parsed_obj["data"]["materials"];
|
||||
if (materials.contains("objects") && materials["objects"].is_array()) {
|
||||
for (const auto &pobj : materials["objects"]) {
|
||||
HelioQuery::SupportedData sp;
|
||||
if (pobj.contains("id") && !pobj["id"].is_null()) { sp.id = pobj["id"].get<std::string>(); }
|
||||
if (pobj.contains("name") && !pobj["id"].is_null()) { sp.name = pobj["name"].get<std::string>(); }
|
||||
if (pobj.contains("alternativeNames") && pobj["alternativeNames"].is_object()) {
|
||||
auto alternativeNames = pobj["alternativeNames"];
|
||||
|
||||
//qidi materials
|
||||
if (alternativeNames.contains("qidistudio") && !alternativeNames["qidistudio"].is_null()) {
|
||||
sp.native_name = alternativeNames["qidistudio"].get<std::string>();
|
||||
}
|
||||
//third party materials
|
||||
else {
|
||||
if (pobj.contains("name") && !pobj["id"].is_null()) { sp.native_name = pobj["name"].get<std::string>(); }
|
||||
}
|
||||
}
|
||||
supported_materials.push_back(sp);
|
||||
}
|
||||
}
|
||||
|
||||
HelioQuery::global_supported_materials.insert(HelioQuery::global_supported_materials.end(), supported_materials.begin(), supported_materials.end());
|
||||
|
||||
if (materials.contains("pageInfo") && materials["pageInfo"].contains("hasNextPage") && materials["pageInfo"]["hasNextPage"].get<bool>()) {
|
||||
HelioQuery::request_support_material(url_copy, key_copy, page_copy + 1);
|
||||
}
|
||||
}
|
||||
} catch (...) {}
|
||||
})
|
||||
.on_error([](std::string body, std::string error, unsigned status) {
|
||||
// BOOST_LOG_TRIVIAL(info) << (boost::format("error: %1%, message: %2%") % error % body).str()
|
||||
})
|
||||
.perform();
|
||||
}
|
||||
|
||||
std::string HelioQuery::get_helio_api_url()
|
||||
{
|
||||
std::string helio_api_url;
|
||||
if (GUI::wxGetApp().app_config->get("region") == "China") {
|
||||
helio_api_url = "https://api.helioam.cn/graphql";
|
||||
} else {
|
||||
helio_api_url = "https://api.helioadditive.com/graphql";
|
||||
}
|
||||
return helio_api_url;
|
||||
}
|
||||
|
||||
std::string HelioQuery::get_helio_pat()
|
||||
{
|
||||
std::string helio_pat;
|
||||
if (GUI::wxGetApp().app_config->get("region") == "China") {
|
||||
helio_pat = GUI::wxGetApp().app_config->get("helio_pat_china");
|
||||
} else {
|
||||
helio_pat = GUI::wxGetApp().app_config->get("helio_pat_other");
|
||||
}
|
||||
return helio_pat;
|
||||
}
|
||||
|
||||
void HelioQuery::set_helio_pat(std::string pat)
|
||||
{
|
||||
if (GUI::wxGetApp().app_config->get("region") == "China") {
|
||||
GUI::wxGetApp().app_config->set("helio_pat_china", pat);
|
||||
} else {
|
||||
GUI::wxGetApp().app_config->set("helio_pat_other", pat);
|
||||
}
|
||||
}
|
||||
|
||||
void HelioQuery::request_pat_token(std::function<void(std::string)> func)
|
||||
{
|
||||
std::string url_copy = "";
|
||||
|
||||
if (GUI::wxGetApp().app_config->get("region") == "China") {
|
||||
url_copy = "https://api.helioam.cn/rest/auth/anonymous_token/qidistudio";
|
||||
}
|
||||
else {
|
||||
url_copy = "https://api.helioadditive.com/rest/auth/anonymous_token/qidistudio";
|
||||
}
|
||||
|
||||
auto http = Http::get(url_copy);
|
||||
http.timeout_connect(20)
|
||||
.timeout_max(100)
|
||||
.on_complete([url_copy, func](std::string body, unsigned status) {
|
||||
//success
|
||||
if (status == 200) {
|
||||
try {
|
||||
nlohmann::json parsed_obj = nlohmann::json::parse(body);
|
||||
if (parsed_obj.contains("pat") && parsed_obj["pat"].is_string()) {
|
||||
func(parsed_obj["pat"].get<std::string>());
|
||||
}
|
||||
else {
|
||||
func("error");
|
||||
}
|
||||
|
||||
}
|
||||
catch (...) {}
|
||||
}
|
||||
else if (status == 429) {
|
||||
func("not_enough");
|
||||
}
|
||||
})
|
||||
.on_error([func](std::string body, std::string error, unsigned status) {
|
||||
if (status == 429) {
|
||||
func("not_enough");
|
||||
}
|
||||
else {
|
||||
func("error");
|
||||
}
|
||||
//BOOST_LOG_TRIVIAL(info) << (boost::format("request pat token error: %1%, message: %2%") % error % body).str());
|
||||
})
|
||||
.perform();
|
||||
}
|
||||
|
||||
|
||||
HelioQuery::PresignedURLResult HelioQuery::create_presigned_url(const std::string helio_api_url, const std::string helio_api_key)
|
||||
{
|
||||
HelioQuery::PresignedURLResult res;
|
||||
std::string query_body = R"( {
|
||||
"query": "query getPresignedUrl($fileName: String!) { getPresignedUrl(fileName: $fileName) { mimeType url key } }",
|
||||
"variables": {
|
||||
"fileName": "test.gcode"
|
||||
}
|
||||
} )";
|
||||
|
||||
auto http = Http::post(helio_api_url);
|
||||
|
||||
http.header("Content-Type", "application/json").header("Authorization", helio_api_key).set_post_body(query_body);
|
||||
|
||||
http.timeout_connect(20)
|
||||
.timeout_max(100)
|
||||
.on_complete([&res](std::string body, unsigned status) {
|
||||
try{
|
||||
nlohmann::json parsed_obj = nlohmann::json::parse(body);
|
||||
res.status = status;
|
||||
if (parsed_obj.contains("error")) {
|
||||
res.error = parsed_obj["error"];
|
||||
}
|
||||
else {
|
||||
res.key = parsed_obj["data"]["getPresignedUrl"]["key"];
|
||||
res.mimeType = parsed_obj["data"]["getPresignedUrl"]["mimeType"];
|
||||
res.url = parsed_obj["data"]["getPresignedUrl"]["url"];
|
||||
}
|
||||
}
|
||||
catch (...){}
|
||||
})
|
||||
.on_error([&res](std::string body, std::string error, unsigned status) {
|
||||
res.error = (boost::format("error: %1%, message: %2%") % error % body).str();
|
||||
res.status = status;
|
||||
})
|
||||
.perform_sync();
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
HelioQuery::UploadFileResult HelioQuery::upload_file_to_presigned_url(const std::string file_path_string, const std::string upload_url)
|
||||
{
|
||||
UploadFileResult res;
|
||||
|
||||
Http http = Http::put(upload_url);
|
||||
boost::filesystem::path file_path(file_path_string);
|
||||
http.header("Content-Type", "application/octet-stream");
|
||||
|
||||
http.set_put_body(file_path)
|
||||
.on_complete([&res](std::string body, unsigned status) {
|
||||
if (status == 200)
|
||||
res.success = true;
|
||||
else
|
||||
res.success = false;
|
||||
})
|
||||
.on_error([&res](std::string body, std::string error, unsigned status) {
|
||||
res.success = false;
|
||||
res.error = (boost::format("status: %1%, error: %2%, %3%") % status % body % error).str();
|
||||
})
|
||||
.perform_sync();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
HelioQuery::CreateGCodeResult HelioQuery::create_gcode(const std::string key,
|
||||
const std::string helio_api_url,
|
||||
const std::string helio_api_key,
|
||||
const std::string printer_id,
|
||||
const std::string filament_id)
|
||||
{
|
||||
HelioQuery::CreateGCodeResult res;
|
||||
std::string query_body_template = R"( {
|
||||
"query": "mutation CreateGcode($input: CreateGcodeInput!) { createGcode(input: $input) { errors gcode { id name sizeKb } } }",
|
||||
"variables": {
|
||||
"input": {
|
||||
"name": "%1%",
|
||||
"printerId": "%2%",
|
||||
"materialId": "%3%",
|
||||
"gcodeKey": "%4%",
|
||||
"isSingleShell": true
|
||||
}
|
||||
}
|
||||
} )";
|
||||
|
||||
std::vector<std::string> key_split;
|
||||
boost::split(key_split, key, boost::is_any_of("/"));
|
||||
|
||||
std::string gcode_name = key_split.back();
|
||||
|
||||
std::string query_body = (boost::format(query_body_template) % gcode_name % printer_id % filament_id % key).str();
|
||||
|
||||
auto http = Http::post(helio_api_url);
|
||||
|
||||
http.header("Content-Type", "application/json").header("Authorization", helio_api_key).set_post_body(query_body);
|
||||
|
||||
http.timeout_connect(20)
|
||||
.timeout_max(100)
|
||||
.on_complete([&res](std::string body, unsigned status) {
|
||||
|
||||
try{
|
||||
nlohmann::json parsed_obj = nlohmann::json::parse(body);
|
||||
res.status = status;
|
||||
if (parsed_obj.contains("errors")) {
|
||||
res.error = parsed_obj["errors"].dump();
|
||||
res.success = false;
|
||||
}
|
||||
else {
|
||||
|
||||
if (!parsed_obj["data"]["createGcode"]["gcode"].is_null()) {
|
||||
res.success = true;
|
||||
res.id = parsed_obj["data"]["createGcode"]["gcode"]["id"];
|
||||
res.name = parsed_obj["data"]["createGcode"]["gcode"]["name"];
|
||||
}
|
||||
else {
|
||||
res.success = false;
|
||||
res.error = "";
|
||||
for (const auto& err : parsed_obj["data"]["createGcode"]["criticalErrors"]) {
|
||||
std::string error_msg = err.get<std::string>();
|
||||
res.error_flags.push_back(error_msg);
|
||||
|
||||
res.error += " ";
|
||||
res.error += error_msg;
|
||||
}
|
||||
|
||||
for (const auto& err : parsed_obj["data"]["createGcode"]["criticalErrors"]) {
|
||||
std::string error_msg = err.get<std::string>();
|
||||
res.error_flags.push_back(error_msg);
|
||||
|
||||
res.error += " ";
|
||||
res.error += error_msg;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& err : parsed_obj["data"]["createGcode"]["warnings"]) {
|
||||
std::string error_msg = err.get<std::string>();
|
||||
res.warning_flags.push_back(error_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...){}
|
||||
})
|
||||
.on_error([&res](std::string body, std::string error, unsigned status) {
|
||||
res.success = false;
|
||||
res.error = error;
|
||||
res.status = status;
|
||||
})
|
||||
.perform_sync();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
std::string HelioQuery::generate_graphql_query(const std::string &gcode_id, float temperatureStabilizationHeight, float airTemperatureAboveBuildPlate, float stabilizedAirTemperature)
|
||||
{
|
||||
std::string name = generateTimestampedString();
|
||||
|
||||
std::string base_query = R"( {
|
||||
"query": "mutation CreateSimulation($input: CreateSimulationInput!) { createSimulation(input: $input) { id name progress status gcode { id name } printer { id name } material { id name } reportJsonUrl thermalIndexGcodeUrl estimatedSimulationDurationSeconds insertedAt updatedAt } }",
|
||||
"variables": {
|
||||
"input": {
|
||||
"name": "%1%",
|
||||
"gcodeId": "%2%",
|
||||
"simulationSettings": {
|
||||
)";
|
||||
|
||||
std::vector<std::string> settings_fields;
|
||||
|
||||
if (temperatureStabilizationHeight != -1) {
|
||||
settings_fields.push_back(boost::str(boost::format(R"( "temperatureStabilizationHeight": %1%)") % temperatureStabilizationHeight));
|
||||
}
|
||||
|
||||
if (airTemperatureAboveBuildPlate != -1) {
|
||||
settings_fields.push_back(boost::str(boost::format(R"( "airTemperatureAboveBuildPlate": %1%)") % airTemperatureAboveBuildPlate));
|
||||
}
|
||||
|
||||
if (stabilizedAirTemperature != -1) {
|
||||
settings_fields.push_back(boost::str(boost::format(R"( "stabilizedAirTemperature": %1%)") % stabilizedAirTemperature));
|
||||
}
|
||||
|
||||
std::string settings_block;
|
||||
if (!settings_fields.empty()) { settings_block = boost::join(settings_fields, ",\n"); }
|
||||
|
||||
std::string full_query = base_query + settings_block + R"(
|
||||
}
|
||||
}
|
||||
}
|
||||
} )";
|
||||
|
||||
boost::format formatter(full_query);
|
||||
formatter % name % gcode_id;
|
||||
|
||||
return formatter.str();
|
||||
}
|
||||
|
||||
HelioQuery::CreateSimulationResult HelioQuery::create_simulation(const std::string helio_api_url,
|
||||
const std::string helio_api_key,
|
||||
const std::string gcode_id,
|
||||
const float initial_room_airtemp,
|
||||
const float layer_threshold,
|
||||
const float object_proximity_airtemp)
|
||||
{
|
||||
HelioQuery::CreateSimulationResult res;
|
||||
|
||||
const float initial_room_temp_kelvin = initial_room_airtemp == -1 ? -1 : initial_room_airtemp + 273.15;
|
||||
const float object_proximity_airtemp_kelvin = object_proximity_airtemp == -1 ? -1 : object_proximity_airtemp + 273.15;
|
||||
const float layer_threshold_meters = layer_threshold / 1000;
|
||||
|
||||
|
||||
|
||||
std::string query_body = generate_graphql_query(gcode_id,
|
||||
layer_threshold_meters,
|
||||
initial_room_temp_kelvin,
|
||||
object_proximity_airtemp_kelvin
|
||||
);
|
||||
|
||||
auto http = Http::post(helio_api_url);
|
||||
|
||||
http.header("Content-Type", "application/json").header("Authorization", helio_api_key).set_post_body(query_body);
|
||||
|
||||
http.timeout_connect(20)
|
||||
.timeout_max(100)
|
||||
.on_complete([&res](std::string body, unsigned status) {
|
||||
|
||||
try{
|
||||
nlohmann::json parsed_obj = nlohmann::json::parse(body);
|
||||
res.status = status;
|
||||
if (parsed_obj.contains("errors")) {
|
||||
res.error = parsed_obj["errors"].dump();
|
||||
res.success = false;
|
||||
}
|
||||
else {
|
||||
res.success = true;
|
||||
res.id = parsed_obj["data"]["createSimulation"]["id"];
|
||||
res.name = parsed_obj["data"]["createSimulation"]["name"];
|
||||
}
|
||||
}
|
||||
catch (...){}
|
||||
})
|
||||
.on_error([&res](std::string body, std::string error, unsigned status) {
|
||||
res.success = false;
|
||||
res.error = error;
|
||||
res.status = status;
|
||||
})
|
||||
.perform_sync();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
HelioQuery::CheckSimulationProgressResult HelioQuery::check_simulation_progress(const std::string helio_api_url,
|
||||
const std::string helio_api_key,
|
||||
const std::string simulation_id)
|
||||
{
|
||||
HelioQuery::CheckSimulationProgressResult res;
|
||||
std::string query_body_template = R"( {
|
||||
"query": "query Simulation($id: ID!) { simulation(id: $id) { id name progress status thermalIndexGcodeUrl } }",
|
||||
"variables": {
|
||||
"id": "%1%"
|
||||
}
|
||||
} )";
|
||||
|
||||
std::string query_body = (boost::format(query_body_template) % simulation_id).str();
|
||||
|
||||
auto http = Http::post(helio_api_url);
|
||||
|
||||
http.header("Content-Type", "application/json").header("Authorization", helio_api_key).set_post_body(query_body);
|
||||
|
||||
http.timeout_connect(20)
|
||||
.timeout_max(100)
|
||||
.on_complete([&res](std::string body, unsigned status) {
|
||||
try{
|
||||
nlohmann::json parsed_obj = nlohmann::json::parse(body);
|
||||
res.status = status;
|
||||
if (parsed_obj.contains("errors")) {
|
||||
res.error = parsed_obj["errors"].dump();
|
||||
}
|
||||
else {
|
||||
res.id = parsed_obj["data"]["simulation"]["id"];
|
||||
res.name = parsed_obj["data"]["simulation"]["name"];
|
||||
res.progress = parsed_obj["data"]["simulation"]["progress"];
|
||||
res.is_finished = parsed_obj["data"]["simulation"]["status"] == "FINISHED";
|
||||
if (res.is_finished)
|
||||
res.url = parsed_obj["data"]["simulation"]["thermalIndexGcodeUrl"];
|
||||
}
|
||||
}
|
||||
catch (...){}
|
||||
})
|
||||
.on_error([&res](std::string body, std::string error, unsigned status) {
|
||||
res.error = error;
|
||||
res.status = status;
|
||||
})
|
||||
.perform_sync();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void HelioBackgroundProcess::helio_thread_start(std::mutex& slicing_mutex,
|
||||
std::condition_variable& slicing_condition,
|
||||
BackgroundSlicingProcess::State& slicing_state,
|
||||
std::unique_ptr<GUI::NotificationManager>& notification_manager)
|
||||
{
|
||||
m_thread = create_thread([this, &slicing_mutex, &slicing_condition, &slicing_state, ¬ification_manager] {
|
||||
this->helio_threaded_process_start(slicing_mutex, slicing_condition, slicing_state, notification_manager);
|
||||
});
|
||||
}
|
||||
|
||||
void HelioBackgroundProcess::helio_threaded_process_start(std::mutex& slicing_mutex,
|
||||
std::condition_variable& slicing_condition,
|
||||
BackgroundSlicingProcess::State& slicing_state,
|
||||
std::unique_ptr<GUI::NotificationManager>& notification_manager)
|
||||
{
|
||||
set_state(STATE_RUNNING);
|
||||
|
||||
std::unique_lock<std::mutex> slicing_lck(slicing_mutex);
|
||||
slicing_condition.wait(slicing_lck, [this, &slicing_state]() {
|
||||
return slicing_state == BackgroundSlicingProcess::STATE_FINISHED || slicing_state == BackgroundSlicingProcess::STATE_CANCELED ||
|
||||
slicing_state == BackgroundSlicingProcess::STATE_IDLE;
|
||||
});
|
||||
slicing_lck.unlock();
|
||||
|
||||
if ((slicing_state == BackgroundSlicingProcess::STATE_FINISHED || slicing_state == BackgroundSlicingProcess::STATE_IDLE) &&
|
||||
!was_canceled()) {
|
||||
wxPostEvent(GUI::wxGetApp().plater(), GUI::SimpleEvent(GUI::EVT_HELIO_PROCESSING_STARTED));
|
||||
|
||||
Slic3r::PrintBase::SlicingStatus status = Slic3r::PrintBase::SlicingStatus(0.0, _u8L("Helio: Process Started"));
|
||||
Slic3r::SlicingStatusEvent* evt = new Slic3r::SlicingStatusEvent(GUI::EVT_SLICING_UPDATE, 0, status);
|
||||
wxQueueEvent(GUI::wxGetApp().plater(), evt);
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << boost::format("url: %1%, key: %2%") % helio_api_url % helio_api_key;
|
||||
|
||||
/*check api url*/
|
||||
if (helio_api_url.empty()) {
|
||||
set_state(STATE_CANCELED);
|
||||
Slic3r::HelioCompletionEvent *evt = new Slic3r::HelioCompletionEvent(GUI::EVT_HELIO_PROCESSING_COMPLETED, 0, "", "", false,
|
||||
_u8L("Helio API endpoint is empty, please check the configuration."));
|
||||
wxQueueEvent(GUI::wxGetApp().plater(), evt);
|
||||
return;
|
||||
}
|
||||
|
||||
/*check Personal assecc token */
|
||||
if (helio_origin_key.empty()) {
|
||||
set_state(STATE_CANCELED);
|
||||
Slic3r::HelioCompletionEvent *evt = new Slic3r::HelioCompletionEvent(GUI::EVT_HELIO_PROCESSING_COMPLETED, 0, "", "", false,
|
||||
_u8L("Personal assecc token is empty, please fill in the correct token."));
|
||||
wxQueueEvent(GUI::wxGetApp().plater(), evt);
|
||||
return;
|
||||
}
|
||||
|
||||
HelioQuery::PresignedURLResult create_presigned_url_res = HelioQuery::create_presigned_url(helio_api_url, helio_api_key);
|
||||
|
||||
if (create_presigned_url_res.error.empty() && create_presigned_url_res.status == 200 && !was_canceled()) {
|
||||
status = Slic3r::PrintBase::SlicingStatus(5, _u8L("Helio: Presigned URL Created"));
|
||||
evt = new Slic3r::SlicingStatusEvent(GUI::EVT_SLICING_UPDATE, 0, status);
|
||||
wxQueueEvent(GUI::wxGetApp().plater(), evt);
|
||||
|
||||
HelioQuery::UploadFileResult upload_file_res = HelioQuery::upload_file_to_presigned_url(m_gcode_result->filename,
|
||||
create_presigned_url_res.url);
|
||||
|
||||
if (upload_file_res.success && !was_canceled()) {
|
||||
status = Slic3r::PrintBase::SlicingStatus(10, _u8L("Helio: file succesfully uploaded"));
|
||||
evt = new Slic3r::SlicingStatusEvent(GUI::EVT_SLICING_UPDATE, 0, status);
|
||||
wxQueueEvent(GUI::wxGetApp().plater(), evt);
|
||||
|
||||
HelioQuery::CreateGCodeResult create_gcode_res = HelioQuery::create_gcode(create_presigned_url_res.key, helio_api_url,
|
||||
helio_api_key, printer_id, filament_id);
|
||||
|
||||
create_simulation_step(create_gcode_res, notification_manager);
|
||||
|
||||
} else {
|
||||
set_state(STATE_CANCELED);
|
||||
|
||||
Slic3r::HelioCompletionEvent* evt = new Slic3r::HelioCompletionEvent(GUI::EVT_HELIO_PROCESSING_COMPLETED, 0, "", "", false,
|
||||
_u8L("Helio: file upload failed"));
|
||||
wxQueueEvent(GUI::wxGetApp().plater(), evt);
|
||||
}
|
||||
} else {
|
||||
std::string presigned_url_message = (boost::format("error: %1%") % create_presigned_url_res.error).str();
|
||||
|
||||
if (create_presigned_url_res.status == 401) {
|
||||
presigned_url_message += "\n ";
|
||||
presigned_url_message += _u8L("Please make sure you have the corrent API key set in preferences.");
|
||||
}
|
||||
|
||||
set_state(STATE_CANCELED);
|
||||
|
||||
Slic3r::HelioCompletionEvent* evt = new Slic3r::HelioCompletionEvent(GUI::EVT_HELIO_PROCESSING_COMPLETED, 0, "", "", false,
|
||||
presigned_url_message);
|
||||
wxQueueEvent(GUI::wxGetApp().plater(), evt);
|
||||
}
|
||||
} else {
|
||||
set_state(STATE_CANCELED);
|
||||
}
|
||||
}
|
||||
|
||||
void HelioBackgroundProcess::create_simulation_step(HelioQuery::CreateGCodeResult create_gcode_res,
|
||||
std::unique_ptr<GUI::NotificationManager>& notification_manager)
|
||||
{
|
||||
if (create_gcode_res.success && !was_canceled()) {
|
||||
Slic3r::PrintBase::SlicingStatus status = Slic3r::PrintBase::SlicingStatus(15, _u8L("Helio: GCode created successfully"));
|
||||
Slic3r::SlicingStatusEvent* evt = new Slic3r::SlicingStatusEvent(GUI::EVT_SLICING_UPDATE, 0, status);
|
||||
wxQueueEvent(GUI::wxGetApp().plater(), evt);
|
||||
|
||||
auto print_config = GUI::wxGetApp().preset_bundle->full_config();
|
||||
const std::string gcode_id = create_gcode_res.id;
|
||||
|
||||
const float chamber_temp = simulation_input_data.chamber_temp; //User input1
|
||||
const float layer_threshold = 20; //Default values from Helio
|
||||
|
||||
std::string bed_temp_key = Slic3r::get_bed_temp_1st_layer_key((Slic3r::BedType)(print_config.option("curr_bed_type")->getInt()));
|
||||
|
||||
const float bed_temp = print_config.option<ConfigOptionInts>(bed_temp_key)->get_at(0);
|
||||
float initial_room_airtemp = -1;
|
||||
if (chamber_temp > 0.0f) {
|
||||
initial_room_airtemp = (chamber_temp + bed_temp) / 2;
|
||||
}
|
||||
|
||||
HelioQuery::CreateSimulationResult create_simulation_res = HelioQuery::create_simulation(helio_api_url, helio_api_key, gcode_id,
|
||||
initial_room_airtemp, layer_threshold,
|
||||
chamber_temp);
|
||||
|
||||
if (create_simulation_res.success && !was_canceled()) {
|
||||
status = Slic3r::PrintBase::SlicingStatus(20, _u8L("Helio: simulation successfully created"));
|
||||
evt = new Slic3r::SlicingStatusEvent(GUI::EVT_SLICING_UPDATE, 0, status);
|
||||
wxQueueEvent(GUI::wxGetApp().plater(), evt);
|
||||
|
||||
int times_tried = 0;
|
||||
int max_unsuccessful_tries = 5;
|
||||
int times_queried = 0;
|
||||
|
||||
while (!was_canceled()) {
|
||||
HelioQuery::CheckSimulationProgressResult check_simulation_progress_res =
|
||||
HelioQuery::check_simulation_progress(helio_api_url, helio_api_key, create_simulation_res.id);
|
||||
|
||||
if (check_simulation_progress_res.status == 200) {
|
||||
times_tried = 0;
|
||||
if (check_simulation_progress_res.error.empty()) {
|
||||
std::string trailing_dots = "";
|
||||
|
||||
for (int i = 0; i < (times_queried % 3); i++) {
|
||||
trailing_dots += "....";
|
||||
}
|
||||
|
||||
status = Slic3r::PrintBase::SlicingStatus(35 + (80 - 35) * check_simulation_progress_res.progress,
|
||||
_u8L("Helio: simulation working") + trailing_dots);
|
||||
evt = new Slic3r::SlicingStatusEvent(GUI::EVT_SLICING_UPDATE, 0, status);
|
||||
wxQueueEvent(GUI::wxGetApp().plater(), evt);
|
||||
if (check_simulation_progress_res.is_finished) {
|
||||
// notification_manager->push_notification((boost::format("Helio: Simulation finished.")).str());
|
||||
std::string simulated_gcode_path = HelioBackgroundProcess::create_path_for_simulated_gcode(
|
||||
m_gcode_result->filename);
|
||||
|
||||
HelioBackgroundProcess::save_downloaded_gcode_and_load_preview(check_simulation_progress_res.url,
|
||||
simulated_gcode_path, m_gcode_result->filename,
|
||||
notification_manager);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
set_state(STATE_CANCELED);
|
||||
|
||||
Slic3r::HelioCompletionEvent* evt = new Slic3r::HelioCompletionEvent(GUI::EVT_HELIO_PROCESSING_COMPLETED, 0, "", "",
|
||||
false, _u8L("Helio: simulation failed"));
|
||||
wxQueueEvent(GUI::wxGetApp().plater(), evt);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
times_tried++;
|
||||
|
||||
status = Slic3r::PrintBase::SlicingStatus(35, (boost::format("Helio: Simulation check failed, %1% tries left") %
|
||||
(max_unsuccessful_tries - times_tried))
|
||||
.str());
|
||||
evt = new Slic3r::SlicingStatusEvent(GUI::EVT_SLICING_UPDATE, 0, status);
|
||||
wxQueueEvent(GUI::wxGetApp().plater(), evt);
|
||||
|
||||
if (times_tried >= max_unsuccessful_tries)
|
||||
break;
|
||||
}
|
||||
|
||||
times_queried++;
|
||||
boost::this_thread ::sleep_for(boost::chrono::seconds(3));
|
||||
}
|
||||
|
||||
} else {
|
||||
set_state(STATE_CANCELED);
|
||||
|
||||
Slic3r::HelioCompletionEvent* evt = new Slic3r::HelioCompletionEvent(GUI::EVT_HELIO_PROCESSING_COMPLETED, 0, "", "", false,
|
||||
(boost::format("Helio: Failed to create Simulation\n%1%") % create_simulation_res.error).str());
|
||||
wxQueueEvent(GUI::wxGetApp().plater(), evt);
|
||||
}
|
||||
|
||||
} else {
|
||||
set_state(STATE_CANCELED);
|
||||
|
||||
Slic3r::HelioCompletionEvent* evt = new Slic3r::HelioCompletionEvent(GUI::EVT_HELIO_PROCESSING_COMPLETED, 0, "", "", false,
|
||||
(boost::format("Helio: Failed to create GCode\n%1%") % create_gcode_res.error).str());
|
||||
wxQueueEvent(GUI::wxGetApp().plater(), evt);
|
||||
}
|
||||
}
|
||||
|
||||
void HelioBackgroundProcess::save_downloaded_gcode_and_load_preview(std::string file_download_url,
|
||||
std::string simulated_gcode_path,
|
||||
std::string tmp_path,
|
||||
std::unique_ptr<GUI::NotificationManager>& notification_manager)
|
||||
{
|
||||
auto http = Http::get(file_download_url);
|
||||
unsigned response_status = 0;
|
||||
std::string downloaded_gcode;
|
||||
std::string response_error;
|
||||
|
||||
int number_of_attempts = 0;
|
||||
int max_attempts = 7;
|
||||
int number_of_seconds_till_next_attempt = 0;
|
||||
|
||||
while (response_status != 200 && !was_canceled()) {
|
||||
if (number_of_seconds_till_next_attempt <= 0) {
|
||||
http.on_complete([&downloaded_gcode, &response_error, &response_status](std::string body, unsigned status) {
|
||||
response_status = status;
|
||||
if (status == 200) {
|
||||
downloaded_gcode = body;
|
||||
} else {
|
||||
response_error = (boost::format("status: %1%, error: %2%") % status % body).str();
|
||||
}
|
||||
})
|
||||
.on_error([&response_error, &response_status](std::string body, std::string error, unsigned status) {
|
||||
response_status = status;
|
||||
response_error = (boost::format("status: %1%, error: %2%") % status % body).str();
|
||||
})
|
||||
.perform_sync();
|
||||
|
||||
if (response_status != 200) {
|
||||
number_of_attempts++;
|
||||
Slic3r::PrintBase::SlicingStatus status = Slic3r::PrintBase::SlicingStatus(
|
||||
80, (boost::format("Helio: Could not download file. Attempts left %1%") % (max_attempts - number_of_attempts)).str());
|
||||
Slic3r::SlicingStatusEvent* evt = new Slic3r::SlicingStatusEvent(GUI::EVT_SLICING_UPDATE, 0, status);
|
||||
wxQueueEvent(GUI::wxGetApp().plater(), evt);
|
||||
number_of_seconds_till_next_attempt = number_of_attempts * 5;
|
||||
}
|
||||
|
||||
if (response_status == 200) {
|
||||
response_error = "";
|
||||
break;
|
||||
}
|
||||
|
||||
else if (number_of_attempts >= max_attempts) {
|
||||
response_error = "Max attempts reached but file was not found";
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
Slic3r::PrintBase::SlicingStatus status = Slic3r::PrintBase::SlicingStatus(80,
|
||||
(boost::format("Helio: Next attemp in %1% seconds") %
|
||||
number_of_seconds_till_next_attempt)
|
||||
.str());
|
||||
Slic3r::SlicingStatusEvent* evt = new Slic3r::SlicingStatusEvent(GUI::EVT_SLICING_UPDATE, 0, status);
|
||||
wxQueueEvent(GUI::wxGetApp().plater(), evt);
|
||||
}
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(1));
|
||||
number_of_seconds_till_next_attempt--;
|
||||
}
|
||||
|
||||
if (response_error.empty() && !was_canceled()) {
|
||||
FILE* file = fopen(simulated_gcode_path.c_str(), "wb");
|
||||
fwrite(downloaded_gcode.c_str(), 1, downloaded_gcode.size(), file);
|
||||
fclose(file);
|
||||
|
||||
Slic3r::PrintBase::SlicingStatus status = Slic3r::PrintBase::SlicingStatus(100, _u8L("Helio: GCode downloaded successfully"));
|
||||
Slic3r::SlicingStatusEvent* evt = new Slic3r::SlicingStatusEvent(GUI::EVT_SLICING_UPDATE, 0, status);
|
||||
wxQueueEvent(GUI::wxGetApp().plater(), evt);
|
||||
HelioBackgroundProcess::load_simulation_to_viwer(simulated_gcode_path, tmp_path);
|
||||
} else {
|
||||
set_state(STATE_CANCELED);
|
||||
|
||||
Slic3r::HelioCompletionEvent* evt =
|
||||
new Slic3r::HelioCompletionEvent(GUI::EVT_HELIO_PROCESSING_COMPLETED, 0, "", "", false,
|
||||
(boost::format("Helio: GCode download failed: %1%") % response_error).str());
|
||||
wxQueueEvent(GUI::wxGetApp().plater(), evt);
|
||||
}
|
||||
}
|
||||
|
||||
void HelioBackgroundProcess::load_simulation_to_viwer(std::string simulated_file_path, std::string tmp_path)
|
||||
{
|
||||
const Vec3d origin = GUI::wxGetApp().plater()->get_partplate_list().get_current_plate_origin();
|
||||
m_gcode_processor.set_xy_offset(origin(0), origin(1));
|
||||
m_gcode_processor.process_file(simulated_file_path);
|
||||
auto res = &m_gcode_processor.result();
|
||||
m_gcode_result = res;
|
||||
|
||||
set_state(STATE_FINISHED);
|
||||
Slic3r::HelioCompletionEvent* evt = new Slic3r::HelioCompletionEvent(GUI::EVT_HELIO_PROCESSING_COMPLETED, 0, simulated_file_path,
|
||||
tmp_path, true);
|
||||
wxQueueEvent(GUI::wxGetApp().plater(), evt);
|
||||
}
|
||||
|
||||
void HelioBackgroundProcess::set_helio_api_key(std::string api_key) { helio_api_key = api_key; }
|
||||
void HelioBackgroundProcess::set_gcode_result(Slic3r::GCodeProcessorResult* gcode_result) { m_gcode_result = gcode_result; }
|
||||
|
||||
} // namespace Slic3r
|
||||
298
src/slic3r/Utils/HelioDragon.hpp
Normal file
298
src/slic3r/Utils/HelioDragon.hpp
Normal file
@@ -0,0 +1,298 @@
|
||||
#ifndef slic3r_HelioDragon_hpp_
|
||||
#define slic3r_HelioDragon_hpp_
|
||||
|
||||
#include <string>
|
||||
#include <wx/string.h>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/asio/ip/address.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <boost/thread.hpp>
|
||||
#include <wx/event.h>
|
||||
|
||||
#include "PrintHost.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "nlohmann/json.hpp"
|
||||
#include "../GUI/BackgroundSlicingProcess.hpp"
|
||||
#include "../GUI/NotificationManager.hpp"
|
||||
#include "libslic3r/GCode/GCodeProcessor.hpp"
|
||||
#include "../GUI/GUI_Preview.hpp"
|
||||
#include "../GUI/Plater.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class DynamicPrintConfig;
|
||||
class Http;
|
||||
class AppConfig;
|
||||
|
||||
class HelioQuery
|
||||
{
|
||||
public:
|
||||
struct PresignedURLResult
|
||||
{
|
||||
std::string key;
|
||||
std::string mimeType;
|
||||
std::string url;
|
||||
unsigned status;
|
||||
std::string error;
|
||||
};
|
||||
|
||||
struct UploadFileResult
|
||||
{
|
||||
bool success;
|
||||
std::string error;
|
||||
};
|
||||
|
||||
struct SupportedData
|
||||
{
|
||||
std::string id;
|
||||
std::string name;
|
||||
std::string native_name;
|
||||
};
|
||||
|
||||
struct CreateGCodeResult
|
||||
{
|
||||
unsigned status;
|
||||
bool success;
|
||||
std::string name;
|
||||
std::string id;
|
||||
std::string error;
|
||||
vector<std::string> warning_flags;
|
||||
vector<std::string> error_flags;
|
||||
};
|
||||
|
||||
struct CreateSimulationResult
|
||||
{
|
||||
unsigned status;
|
||||
bool success;
|
||||
std::string name;
|
||||
std::string id;
|
||||
std::string error;
|
||||
};
|
||||
|
||||
struct CheckSimulationProgressResult
|
||||
{
|
||||
unsigned status;
|
||||
bool is_finished;
|
||||
float progress;
|
||||
std::string id;
|
||||
std::string name;
|
||||
std::string url;
|
||||
std::string error;
|
||||
};
|
||||
|
||||
static std::string get_helio_api_url();
|
||||
static std::string get_helio_pat();
|
||||
static void set_helio_pat(std::string pat);
|
||||
static void request_support_machine(const std::string helio_api_url, const std::string helio_api_key, int page);
|
||||
static void request_support_material(const std::string helio_api_url, const std::string helio_api_key, int page);
|
||||
static void request_pat_token(std::function<void(std::string)> func);
|
||||
static PresignedURLResult create_presigned_url(const std::string helio_api_url, const std::string helio_api_key);
|
||||
static UploadFileResult upload_file_to_presigned_url(const std::string file_path_string, const std::string upload_url);
|
||||
static CreateGCodeResult create_gcode(const std::string key,
|
||||
const std::string helio_api_url,
|
||||
const std::string helio_api_key,
|
||||
const std::string printer_id,
|
||||
const std::string filament_id);
|
||||
|
||||
static void request_all_support_machine(const std::string helio_api_url, const std::string helio_api_key)
|
||||
{
|
||||
global_supported_printers.clear();
|
||||
request_support_machine(helio_api_url, helio_api_key, 1);
|
||||
}
|
||||
|
||||
static void request_all_support_materials(const std::string helio_api_url, const std::string helio_api_key)
|
||||
{
|
||||
global_supported_materials.clear();
|
||||
request_support_material(helio_api_url, helio_api_key, 1);
|
||||
}
|
||||
|
||||
static CreateSimulationResult create_simulation(const std::string helio_api_url,
|
||||
const std::string helio_api_key,
|
||||
const std::string gcode_id,
|
||||
const float initial_room_airtemp,
|
||||
const float layer_threshold,
|
||||
const float object_proximity_airtemp);
|
||||
|
||||
static CheckSimulationProgressResult check_simulation_progress(const std::string helio_api_url,
|
||||
const std::string helio_api_key,
|
||||
const std::string simulation_id);
|
||||
|
||||
static std::string generate_graphql_query(const std::string &gcode_id, float temperatureStabilizationHeight = -1, float airTemperatureAboveBuildPlate = -1, float stabilizedAirTemperature = -1);
|
||||
static std::string generateTimestampedString()
|
||||
{
|
||||
// Get the current UTC time
|
||||
boost::posix_time::ptime now = boost::posix_time::second_clock::universal_time();
|
||||
|
||||
// Format as ISO 8601 (e.g., "2025-03-12T14:23:45")
|
||||
std::string iso_datetime = boost::posix_time::to_iso_extended_string(now);
|
||||
|
||||
// Combine with your desired prefix
|
||||
return "QIDISlicer " + iso_datetime;
|
||||
}
|
||||
|
||||
static std::vector<SupportedData> global_supported_printers;
|
||||
static std::vector<SupportedData> global_supported_materials;
|
||||
};
|
||||
|
||||
class HelioBackgroundProcess
|
||||
{
|
||||
public:
|
||||
struct SimulationInput
|
||||
{
|
||||
float chamber_temp{-1};
|
||||
};
|
||||
|
||||
public:
|
||||
enum State {
|
||||
// m_thread is not running yet, or it did not reach the STATE_IDLE yet (it does not wait on the condition yet).
|
||||
STATE_INITIAL = 0,
|
||||
STATE_STARTED,
|
||||
STATE_RUNNING,
|
||||
STATE_FINISHED,
|
||||
STATE_CANCELED,
|
||||
};
|
||||
|
||||
private:
|
||||
State m_state;
|
||||
|
||||
public:
|
||||
std::mutex m_mutex;
|
||||
std::condition_variable m_condition;
|
||||
boost::thread m_thread;
|
||||
std::string helio_origin_key;
|
||||
std::string helio_api_key;
|
||||
std::string helio_api_url;
|
||||
std::string printer_id;
|
||||
std::string filament_id;
|
||||
|
||||
//for user input
|
||||
SimulationInput simulation_input_data;
|
||||
|
||||
Slic3r::GCodeProcessorResult* m_gcode_result;
|
||||
Slic3r::GCodeProcessor m_gcode_processor;
|
||||
Slic3r::GUI::Preview* m_preview;
|
||||
std::function<void()> m_update_function;
|
||||
|
||||
void set_simulation_input_data(SimulationInput data)
|
||||
{
|
||||
simulation_input_data = data;
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
m_mutex.lock();
|
||||
m_state = STATE_CANCELED;
|
||||
m_mutex.unlock();
|
||||
}
|
||||
|
||||
bool is_running()
|
||||
{
|
||||
m_mutex.lock();
|
||||
bool running_state = (m_state == STATE_STARTED || m_state == STATE_RUNNING);
|
||||
m_mutex.unlock();
|
||||
|
||||
return running_state;
|
||||
}
|
||||
|
||||
bool was_canceled()
|
||||
{
|
||||
m_mutex.lock();
|
||||
bool canceled_state = (m_state == STATE_CANCELED);
|
||||
m_mutex.unlock();
|
||||
return canceled_state;
|
||||
}
|
||||
|
||||
void set_state(State state)
|
||||
{
|
||||
m_mutex.lock();
|
||||
m_state = state;
|
||||
m_mutex.unlock();
|
||||
}
|
||||
|
||||
State get_state()
|
||||
{
|
||||
m_mutex.lock();
|
||||
auto state = m_state;
|
||||
m_mutex.unlock();
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
void helio_threaded_process_start(std::mutex& slicing_mutex,
|
||||
std::condition_variable& slicing_condition,
|
||||
BackgroundSlicingProcess::State& slicing_state,
|
||||
std::unique_ptr<GUI::NotificationManager>& notification_manager);
|
||||
|
||||
void helio_thread_start(std::mutex& slicing_mutex,
|
||||
std::condition_variable& slicing_condition,
|
||||
BackgroundSlicingProcess::State& slicing_state,
|
||||
std::unique_ptr<GUI::NotificationManager>& notification_manager);
|
||||
|
||||
HelioBackgroundProcess() {}
|
||||
|
||||
~HelioBackgroundProcess()
|
||||
{
|
||||
m_gcode_result = nullptr;
|
||||
if (m_thread.joinable()) {
|
||||
m_thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
void init(std::string api_key,
|
||||
std::string api_url,
|
||||
std::string printer_id,
|
||||
std::string filament_id,
|
||||
Slic3r::GCodeProcessorResult* gcode_result,
|
||||
Slic3r::GUI::Preview* preview,
|
||||
std::function<void()> function)
|
||||
{
|
||||
m_state = STATE_STARTED;
|
||||
m_gcode_processor.reset();
|
||||
helio_origin_key = api_key;
|
||||
helio_api_key = "Bearer " + api_key;
|
||||
helio_api_url = api_url;
|
||||
this->printer_id = printer_id;
|
||||
this->filament_id = filament_id;
|
||||
m_gcode_result = gcode_result;
|
||||
m_preview = preview;
|
||||
m_update_function = function;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
m_state = STATE_INITIAL;
|
||||
m_gcode_processor.reset();
|
||||
m_gcode_result = nullptr;
|
||||
}
|
||||
|
||||
void set_helio_api_key(std::string api_key);
|
||||
void set_gcode_result(Slic3r::GCodeProcessorResult* gcode_result);
|
||||
void create_simulation_step(HelioQuery::CreateGCodeResult create_gcode_res,
|
||||
std::unique_ptr<GUI::NotificationManager>& notification_manager);
|
||||
void save_downloaded_gcode_and_load_preview(std::string file_download_url,
|
||||
std::string simulated_gcode_path,
|
||||
std::string tmp_path,
|
||||
std::unique_ptr<GUI::NotificationManager>& notification_manager);
|
||||
|
||||
std::string create_path_for_simulated_gcode(std::string unsimulated_gcode_path)
|
||||
{
|
||||
boost::filesystem::path p(unsimulated_gcode_path);
|
||||
|
||||
if (!p.has_filename()) {
|
||||
throw std::runtime_error("Invalid path: No filename present.");
|
||||
}
|
||||
|
||||
boost::filesystem::path parent = p.parent_path();
|
||||
std::string new_filename = "simulated_" + p.filename().string();
|
||||
|
||||
return (parent / new_filename).string();
|
||||
}
|
||||
|
||||
void load_simulation_to_viwer(std::string file_path, std::string tmp_path);
|
||||
};
|
||||
} // namespace Slic3r
|
||||
#endif
|
||||
@@ -112,7 +112,6 @@ struct Http::priv
|
||||
std::string headers;
|
||||
size_t limit;
|
||||
bool cancel;
|
||||
std::unique_ptr<fs::ifstream> putFile;
|
||||
|
||||
std::thread io_thread;
|
||||
Http::CompleteFn completefn;
|
||||
@@ -260,10 +259,8 @@ size_t Http::priv::form_file_read_cb(char *buffer, size_t size, size_t nitems, v
|
||||
{
|
||||
//y65
|
||||
// try {
|
||||
// auto putFile = reinterpret_cast<std::unique_ptr<fs::ifstream>*>(userp);
|
||||
// if (!putFile) { throw std::runtime_error(std::string("The unique_ptr is nullptr! please check")); return CURL_READFUNC_ABORT; }
|
||||
// auto fstream = static_cast<fs::ifstream *>(userp)
|
||||
|
||||
// fs::ifstream* fstream = putFile->get();
|
||||
// if (!fstream) { throw std::runtime_error(std::string("The fstream is nullptr! please check")); return CURL_READFUNC_ABORT; }
|
||||
|
||||
|
||||
@@ -380,9 +377,10 @@ void Http::priv::set_put_body(const fs::path &path)
|
||||
boost::system::error_code ec;
|
||||
boost::uintmax_t filesize = file_size(path, ec);
|
||||
if (!ec) {
|
||||
putFile = std::make_unique<fs::ifstream>(path, std::ios_base::binary |std::ios_base::in);
|
||||
form_files.emplace_back(path, std::ios_base::binary |std::ios_base::in);
|
||||
auto &putFile = form_files.back();
|
||||
::curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
|
||||
::curl_easy_setopt(curl, CURLOPT_READDATA, (void *) &putFile);
|
||||
::curl_easy_setopt(curl, CURLOPT_READDATA, static_cast<void*>(&putFile));
|
||||
::curl_easy_setopt(curl, CURLOPT_INFILESIZE, filesize);
|
||||
}
|
||||
}
|
||||
@@ -502,11 +500,6 @@ Http::Http(Http &&other) : p(std::move(other.p)) {}
|
||||
|
||||
Http::~Http()
|
||||
{
|
||||
if (p && p->putFile)
|
||||
{
|
||||
p->putFile.reset();
|
||||
}
|
||||
|
||||
if (p && p->io_thread.joinable()) {
|
||||
p->io_thread.detach();
|
||||
}
|
||||
|
||||
@@ -747,10 +747,11 @@ void PresetUpdater::priv::parse_ota_files(std::string ota_json, std::string& ver
|
||||
if (j.contains("description"))
|
||||
description = j["description"];
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(": ota_json %1%, version %2%, force %3%, description %4%")%ota_json %version %force_upgrade %description;
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__
|
||||
<< boost::format(": ota_json %1%, version %2%, force %3%, description %4%") % PathSanitizer::sanitize(ota_json) % version % force_upgrade % description;
|
||||
}
|
||||
catch(nlohmann::detail::parse_error &err) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": parse "<<ota_json<<" got a nlohmann::detail::parse_error, reason = " << err.what();
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": parse " << PathSanitizer::sanitize(ota_json) << " got a nlohmann::detail::parse_error, reason = " << err.what();
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace QDT {
|
||||
#define QIDI_NETWORK_LIBRARY "qidi_networking"
|
||||
#define QIDI_NETWORK_AGENT_NAME "qidi_network_agent"
|
||||
|
||||
#define QIDI_NETWORK_AGENT_VERSION "02.02.00.55"
|
||||
#define QIDI_NETWORK_AGENT_VERSION "02.02.01.51"
|
||||
|
||||
//iot preset type strings
|
||||
#define IOT_PRINTER_TYPE_STRING "printer"
|
||||
@@ -231,6 +231,7 @@ struct PrintParams {
|
||||
std::string task_bed_type;
|
||||
std::string extra_options;
|
||||
int auto_bed_leveling{ 0 };
|
||||
int enable_multi_box{0};
|
||||
int auto_flow_cali{ 0 };
|
||||
int auto_offset_cali{ 0 };
|
||||
bool task_ext_change_assist;
|
||||
|
||||
Reference in New Issue
Block a user