Serialize parameters from json var to config opt format

improved config options filtering

changed outgoing json for upload to connect
This commit is contained in:
David Kocik 2024-08-08 10:58:52 +02:00 committed by Lukas Matena
parent a627c4c64e
commit eb7f27c83d
4 changed files with 154 additions and 55 deletions

View File

@ -3828,9 +3828,7 @@ namespace {
const Preset* find_preset_by_nozzle_and_options(
const PrinterPresetCollection& collection
, const std::string& model_id
, const std::string& nozzle
, const std::map<std::string
, std::string>& options)
, std::map<std::string, std::vector<std::string>>& options)
{
// find all matching presets when repo prefix is ommited
std::vector<const Preset*> results;
@ -3854,33 +3852,39 @@ const Preset* find_preset_by_nozzle_and_options(
if (!preset.is_system || printer_model != model_id)
continue;
// nozzle diameter
if (!nozzle.empty() && preset.config.has("nozzle_diameter")) {
double nozzle_diameter = static_cast<const ConfigOptionFloats*>(preset.config.option("nozzle_diameter"))->values[0];
std::string nozzle_diameter_serialized = into_u8(double_to_string(nozzle_diameter));
if (size_t pos = nozzle_diameter_serialized.find(",") != std::string::npos) {
nozzle_diameter_serialized.replace(pos, 1, 1, '.');
}
if (nozzle != nozzle_diameter_serialized) {
continue;
}
}
// other options
// options (including nozzle_diameter)
bool failed = false;
for (const auto& opt : options) {
if (!preset.config.has(opt.first)) {
failed = true;
break;
assert(preset.config.has(opt.first));
// We compare only first value now, but options contains data for all (some might be empty tho)
std::string opt_val;
if (preset.config.option(opt.first)->is_scalar()) {
opt_val = preset.config.option(opt.first)->serialize();
} else {
switch (preset.config.option(opt.first)->type()) {
case coInts: opt_val = std::to_string(static_cast<const ConfigOptionInts*>(preset.config.option(opt.first))->values[0]); break;
case coFloats:
opt_val = into_u8(double_to_string(static_cast<const ConfigOptionFloats*>(preset.config.option(opt.first))->values[0]));
if (size_t pos = opt_val.find(",") != std::string::npos)
opt_val.replace(pos, 1, 1, '.');
break;
case coStrings: opt_val = static_cast<const ConfigOptionStrings*>(preset.config.option(opt.first))->values[0]; break;
case coBools: opt_val = static_cast<const ConfigOptionBools*>(preset.config.option(opt.first))->values[0] ? "1" : "0"; break;
default:
assert(true);
continue;
}
}
if (preset.config.option(opt.first)->serialize() != opt.second) {
if (opt_val != opt.second[0])
{
failed = true;
break;
}
}
if (failed) {
continue;
if (!failed) {
results.push_back(&preset);
}
results.push_back(&preset);
}
// find visible without prefix
for (const Preset *preset : results) {
@ -3924,12 +3928,23 @@ bool GUI_App::select_printer_from_connect(const std::string& msg)
BOOST_LOG_TRIVIAL(error) << "Failed to select printer from Connect. Printer_model is empty.";
return false;
}
std::string nozzle = UserAccountUtils::get_nozzle_from_json(ptree);
std::map<std::string, std::string> config_options_to_match;
std::map<std::string, std::vector<std::string>> config_options_to_match;
UserAccountUtils::fill_config_options_from_json(ptree, config_options_to_match);
BOOST_LOG_TRIVIAL(info) << "Select printer from Connect. Model: " << model_name << "nozzle: " << nozzle;
// prevent not having nozzle diameter
if (config_options_to_match.find("nozzle_diameter") == config_options_to_match.end()) {
std::string diameter = UserAccountUtils::get_keyword_from_json(ptree, msg, "nozzle_diameter");
if (!diameter.empty())
config_options_to_match["nozzle_diameter"] = {diameter};
}
// log
BOOST_LOG_TRIVIAL(info) << "Select printer from Connect. Model: " << model_name;
for(const auto& pair :config_options_to_match) {
std::string out;
for(const std::string& val :pair.second) { out += val + ",";}
BOOST_LOG_TRIVIAL(info) << pair.first << ": " << out;
}
// select printer
const Preset* printer_preset = find_preset_by_nozzle_and_options(preset_bundle->printers, model_name, nozzle, config_options_to_match);
const Preset* printer_preset = find_preset_by_nozzle_and_options(preset_bundle->printers, model_name, config_options_to_match);
bool is_installed = printer_preset && select_printer_preset(printer_preset);
// notification
std::string out = printer_preset ?
@ -4031,6 +4046,9 @@ void GUI_App::select_filament_from_connect(const std::string& msg)
size_t extruder_count = preset_bundle->extruders_filaments.size();
if (extruder_count != materials.size()) {
BOOST_LOG_TRIVIAL(error) << format("Failed to select filament from Connect. Selected printer has %1% extruders while data from Connect contains %2% materials.", extruder_count, materials.size());
plater()->get_notification_manager()->close_notification_of_type(NotificationType::SelectFilamentFromConnect);
// TRN: Notification text.
plater()->get_notification_manager()->push_notification(NotificationType::SelectFilamentFromConnect, NotificationManager::NotificationLevel::ImportantNotificationLevel, _u8L("Failed to select filament from Connect."));
return;
}
std::string notification_text;
@ -4065,7 +4083,6 @@ void GUI_App::handle_connect_request_printer_select_inner(const std::string & ms
BOOST_LOG_TRIVIAL(debug) << "Handling web request: " << msg;
// return to plater
this->mainframe->select_tab(size_t(0));
if (!select_printer_from_connect(msg)) {
// If printer was not selected, do not select filament.
return;

View File

@ -11,7 +11,7 @@ namespace pt = boost::property_tree;
namespace Slic3r { namespace GUI { namespace UserAccountUtils {
namespace {
std::string parse_tree_for_param(const pt::ptree &tree, const std::string &param) {
std::string parse_tree_for_param(const pt::ptree& tree, const std::string& param) {
for (const auto &section : tree) {
if (section.first == param) {
return section.second.data();
@ -24,8 +24,7 @@ std::string parse_tree_for_param(const pt::ptree &tree, const std::string &param
}
void parse_tree_for_param_vector(
const pt::ptree &tree, const std::string &param, std::vector<std::string> &results
) {
const pt::ptree &tree, const std::string& param, std::vector<std::string>& results) {
for (const auto &section : tree) {
if (section.first == param) {
results.emplace_back(section.second.data());
@ -35,7 +34,7 @@ void parse_tree_for_param_vector(
}
}
pt::ptree parse_tree_for_subtree(const pt::ptree &tree, const std::string &param) {
pt::ptree parse_tree_for_subtree(const pt::ptree& tree, const std::string& param) {
for (const auto &section : tree) {
if (section.first == param) {
return section.second;
@ -47,7 +46,7 @@ pt::ptree parse_tree_for_subtree(const pt::ptree &tree, const std::string &param
return pt::ptree();
}
void json_to_ptree(boost::property_tree::ptree &ptree, const std::string &json) {
void json_to_ptree(boost::property_tree::ptree& ptree, const std::string& json) {
try {
std::stringstream ss(json);
pt::read_json(ss, ptree);
@ -59,7 +58,7 @@ void json_to_ptree(boost::property_tree::ptree &ptree, const std::string &json)
} // namespace
std::string get_nozzle_from_json(boost::property_tree::ptree &ptree) {
std::string get_nozzle_from_json(boost::property_tree::ptree& ptree) {
assert(!ptree.empty());
std::string out = parse_tree_for_param(ptree, "nozzle_diameter");
@ -74,7 +73,7 @@ std::string get_nozzle_from_json(boost::property_tree::ptree &ptree) {
return out;
}
std::string get_keyword_from_json(boost::property_tree::ptree &ptree, const std::string &json, const std::string &keyword )
std::string get_keyword_from_json(boost::property_tree::ptree& ptree, const std::string& json, const std::string& keyword )
{
if (ptree.empty()) {
json_to_ptree(ptree, json);
@ -83,7 +82,7 @@ std::string get_keyword_from_json(boost::property_tree::ptree &ptree, const std:
return parse_tree_for_param(ptree, keyword);
}
void fill_supported_printer_models_from_json(boost::property_tree::ptree &ptree, std::vector<std::string> &result)
void fill_supported_printer_models_from_json(boost::property_tree::ptree& ptree, std::vector<std::string>& result)
{
assert(!ptree.empty());
std::string printer_model = parse_tree_for_param(ptree, "printer_model");
@ -102,16 +101,87 @@ void fill_supported_printer_models_from_json(boost::property_tree::ptree &ptree,
}
}
void fill_config_options_from_json(boost::property_tree::ptree& ptree, std::map<std::string, std::string>& result)
namespace {
std::string json_var_to_opt_string(const std::string& json_var)
{
if (json_var == "true")
return "1";
if (json_var == "false")
return "0";
return json_var;
}
}
void fill_config_options_from_json(boost::property_tree::ptree& ptree, std::map<std::string, std::vector<std::string>>& result)
{
assert(!ptree.empty());
pt::ptree subtree = parse_tree_for_subtree(ptree, "printerConfig");
for (const auto &item : subtree) {
result[item.first] = item.second.data();
/*
"slot": {
"active": 3,
"slots": {
"1": {
"material": "PETG",
"temp": 32.0,
"fan_hotend": 0.0,
"fan_print": 0.0,
"nozzle_diameter": 3.2, // float
"high_flow": true, // boolean
"high_temperature": false, // boolean
"hardened": true, // boolean
},
"3": {
"material": "ASA",
"temp": 35.0,
"fan_hotend": 0.0,
"fan_print": 0.0,
"nozzle_diameter": 3.2, // float
"high_flow": true, // boolean
"high_temperature": false, // boolean
"hardened": true, // boolean
},
}
}
*/
const std::map<std::string, std::string> parameters = {
// first name from connect, second config option
{"nozzle_diameter","nozzle_diameter"},
{"high_flow","nozzle_high_flow"},
//{"",""}
};
pt::ptree slots = parse_tree_for_subtree(parse_tree_for_subtree(ptree, "slot"), "slots");
for (const auto &subtree : slots) {
size_t slot_id;
try {
slot_id = boost::lexical_cast<size_t>(subtree.first);
} catch (const boost::bad_lexical_cast&) {
continue;
}
for (const auto &item : subtree.second) {
if (parameters.find(item.first) == parameters.end()) {
continue;
}
std::string config_name = parameters.at(item.first);
// resolve value
std::string val;
if (item.second.size() > 0) {
for (const auto &subitem : item.second) {
if (!val.empty()) {
val += ",";
}
val += json_var_to_opt_string(subitem.second.data());
}
} else {
val = json_var_to_opt_string(item.second.data());
}
// insert value
while (result[config_name].size() < slot_id)
result[config_name].emplace_back();
result[config_name][slot_id - 1] = val;
}
}
}
void fill_material_from_json(const std::string &json, std::vector<std::string> &result)
void fill_material_from_json(const std::string& json, std::vector<std::string>& result)
{
pt::ptree ptree;
json_to_ptree(ptree, json);
@ -178,10 +248,26 @@ void fill_material_from_json(const std::string &json, std::vector<std::string> &
return;
}
// search "slot" subtree for all "material"s
parse_tree_for_param_vector(slot_subtree, "material", result);
// this parses "slots" with respect to numbers of slots and adds empty string to missing numbers
// if only filled should be used. Use: parse_tree_for_param_vector(slot_subtree, "material", result);
pt::ptree slots = parse_tree_for_subtree(slot_subtree, "slots");
assert(!slots.empty());
for (const auto &subtree : slots) {
size_t slot_id;
try {
slot_id = boost::lexical_cast<size_t>(subtree.first);
} catch (const boost::bad_lexical_cast&) {
continue;
}
std::string val = parse_tree_for_param(subtree.second, "material");
// add empty for missing id
while (result.size() < slot_id)
result.emplace_back();
result[slot_id - 1] = val;
}
}
std::string get_print_data_from_json(const std::string &json, const std::string &keyword) {
std::string get_print_data_from_json(const std::string& json, const std::string& keyword) {
// copy subtree string f.e.
// { "<keyword>": {"param1": "something", "filename":"abcd.gcode", "param3":true},
// "something_else" : 0 } into: {"param1": "something", "filename":"%1%", "param3":true,

View File

@ -15,7 +15,7 @@ std::string get_keyword_from_json(boost::property_tree::ptree& ptree, const std:
// Only ptree is passed since these functions are called on places that already has the ptree from get_keyword_from_json call
std::string get_nozzle_from_json(boost::property_tree::ptree &ptree);
void fill_supported_printer_models_from_json(boost::property_tree::ptree& ptree, std::vector<std::string>& result);
void fill_config_options_from_json(boost::property_tree::ptree& ptree, std::map<std::string, std::string>& result);
void fill_config_options_from_json(boost::property_tree::ptree& ptree, std::map<std::string,std::vector<std::string>>& result);
// Since fill_material_from_json is called only from one place where ptree doesnt need to be shared, it is not always read from json.
void fill_material_from_json(const std::string& json, std::vector<std::string>& result);

View File

@ -1288,8 +1288,10 @@ void PrinterPickWebViewDialog::request_compatible_printers_FFF() {
nozzle_diameter_serialized.Replace(L",", L".");
// Sending only first filament type for now. This should change to array of values
const std::string filament_type_serialized = full_config.option("filament_type")->serialize();
std::string printer_model_serialized = full_config.option("printer_model")->serialize();
const std::string nozzle_high_flow_serialized = static_cast<const ConfigOptionBools *>(full_config.option("nozzle_high_flow"))->values[0] ? "1" : "0";
const std::string filament_abrasive_serialized = static_cast<const ConfigOptionBools *>(full_config.option("filament_abrasive"))->values[0] ? "1" : "0";
std::string printer_model_serialized = full_config.option("printer_model")->serialize();
std::string vendor_repo_prefix;
if (selected_printer.vendor) {
vendor_repo_prefix = selected_printer.vendor->repo_prefix;
@ -1311,19 +1313,13 @@ void PrinterPickWebViewDialog::request_compatible_printers_FFF() {
"{"
"\"printerUuid\": \"%4%\", "
"\"printerModel\": \"%3%\", "
"\"nozzleDiameter\": %2%, "
"\"nozzle_diameter\": %2%, "
"\"material\": \"%1%\", "
"\"filename\": \"%5%\", "
"\"fullConfig\": {"
, filament_type_serialized, nozzle_diameter_serialized, printer_model_serialized, uuid, filename);
for (auto it = full_config.cbegin(); it != full_config.cend(); ++it) {
std::string value = full_config.option(it->first)->serialize();
boost::algorithm::replace_all(value, "\"", "\\\"");
request += it == full_config.cbegin() ? "" : ",";
request += GUI::format("\"%1%\": \"%2%\"", it->first, value);
}
request += "}}";
"\"filament_abrasive\": \"%6%\","
"\"nozzle_high_flow\": \"%7%\""
"}"
, filament_type_serialized, nozzle_diameter_serialized, printer_model_serialized, uuid, filename, nozzle_high_flow_serialized, filament_abrasive_serialized);
wxString script = GUI::format_wxstr("window._prusaConnect_v1.requestCompatiblePrinter(%1%)", request);
run_script(script);