#include "print_params_io.hpp" #include #include #include #include namespace obn::plugin_runner { namespace { using json = nlohmann::json; // Per-type setters. Each returns true if it actually mutated `dst`; the // caller decides what to log. bool set_string(const json& src, const char* key, std::string& dst, std::vector& warnings) { auto it = src.find(key); if (it == src.end()) return false; if (!it->is_string()) { warnings.emplace_back(std::string("'") + key + "' must be a string, ignoring"); return false; } dst = it->get(); return true; } bool set_int(const json& src, const char* key, int& dst, std::vector& warnings) { auto it = src.find(key); if (it == src.end()) return false; if (!it->is_number_integer()) { warnings.emplace_back(std::string("'") + key + "' must be an integer, ignoring"); return false; } dst = it->get(); return true; } bool set_bool(const json& src, const char* key, bool& dst, std::vector& warnings) { auto it = src.find(key); if (it == src.end()) return false; if (!it->is_boolean()) { warnings.emplace_back(std::string("'") + key + "' must be a boolean, ignoring"); return false; } dst = it->get(); return true; } // Allow-list of every PrintParams field this loader knows how to set. // Anything else in the JSON triggers a `params_warning` event so users // notice typos instead of silently sending defaults. Keep in sync with // `BBL::PrintParams` in include/obn/bambu_networking.hpp (the snapshots // under tools/abi_snapshot/v/ are the canonical record per // ABI version) and with the per-field setter calls in // load_print_params_overrides() below. const std::unordered_set kKnownKeys = { "dev_id", "task_name", "project_name", "preset_name", "filename", "config_filename", "plate_index", "ftp_folder", "ftp_file", "ftp_file_md5", "nozzle_mapping", "ams_mapping", "ams_mapping2", "ams_mapping_info", "nozzles_info", "connection_type", "comments", "origin_profile_id", "stl_design_id", "origin_model_id", "print_type", "dst_file", "dev_name", "dev_ip", "use_ssl_for_ftp", "use_ssl_for_mqtt", "username", "password", "task_bed_leveling", "task_flow_cali", "task_vibration_cali", "task_layer_inspect", "task_record_timelapse", #if ABI_VERSION >= 0x020503 "task_timelapse_use_internal", #endif "task_use_ams", "task_bed_type", "extra_options", "auto_bed_leveling", "auto_flow_cali", "auto_offset_cali", #if ABI_VERSION >= 0x020400 "extruder_cali_manual_mode", #endif "task_ext_change_assist", "try_emmc_print", #if ABI_VERSION >= 0x020701 "svc_context", #endif #if ABI_VERSION >= 0x020801 "slicer_uid", #endif #if ABI_VERSION >= 0x020802 "queue_plate_id", #endif }; void warn_unknown(const json& src, std::vector& warnings) { for (auto it = src.begin(); it != src.end(); ++it) { const std::string& key = it.key(); if (kKnownKeys.find(key) == kKnownKeys.end()) { warnings.emplace_back("unknown key '" + key + "' in params JSON — ignoring"); } } } void apply_overlay(const json& j, BBL::PrintParams& p, std::vector& w) { set_string(j, "dev_id", p.dev_id, w); set_string(j, "task_name", p.task_name, w); set_string(j, "project_name", p.project_name, w); set_string(j, "preset_name", p.preset_name, w); set_string(j, "filename", p.filename, w); set_string(j, "config_filename", p.config_filename, w); set_int (j, "plate_index", p.plate_index, w); set_string(j, "ftp_folder", p.ftp_folder, w); set_string(j, "ftp_file", p.ftp_file, w); set_string(j, "ftp_file_md5", p.ftp_file_md5, w); set_string(j, "nozzle_mapping", p.nozzle_mapping, w); set_string(j, "ams_mapping", p.ams_mapping, w); set_string(j, "ams_mapping2", p.ams_mapping2, w); set_string(j, "ams_mapping_info", p.ams_mapping_info, w); set_string(j, "nozzles_info", p.nozzles_info, w); set_string(j, "connection_type", p.connection_type, w); set_string(j, "comments", p.comments, w); set_int (j, "origin_profile_id", p.origin_profile_id, w); set_int (j, "stl_design_id", p.stl_design_id, w); set_string(j, "origin_model_id", p.origin_model_id, w); set_string(j, "print_type", p.print_type, w); set_string(j, "dst_file", p.dst_file, w); set_string(j, "dev_name", p.dev_name, w); set_string(j, "dev_ip", p.dev_ip, w); set_bool (j, "use_ssl_for_ftp", p.use_ssl_for_ftp, w); set_bool (j, "use_ssl_for_mqtt", p.use_ssl_for_mqtt, w); set_string(j, "username", p.username, w); set_string(j, "password", p.password, w); set_bool (j, "task_bed_leveling", p.task_bed_leveling, w); set_bool (j, "task_flow_cali", p.task_flow_cali, w); set_bool (j, "task_vibration_cali", p.task_vibration_cali, w); set_bool (j, "task_layer_inspect", p.task_layer_inspect, w); set_bool (j, "task_record_timelapse", p.task_record_timelapse, w); #if ABI_VERSION >= 0x020503 set_bool (j, "task_timelapse_use_internal", p.task_timelapse_use_internal, w); #else if (j.contains("task_timelapse_use_internal")) { w.emplace_back("'task_timelapse_use_internal' present but ABI < 0x020503; " "skipping (rebuild plugin_runner with newer --abi)"); } #endif set_bool (j, "task_use_ams", p.task_use_ams, w); set_string(j, "task_bed_type", p.task_bed_type, w); set_string(j, "extra_options", p.extra_options, w); set_int (j, "auto_bed_leveling", p.auto_bed_leveling, w); set_int (j, "auto_flow_cali", p.auto_flow_cali, w); set_int (j, "auto_offset_cali", p.auto_offset_cali, w); #if ABI_VERSION >= 0x020400 set_int (j, "extruder_cali_manual_mode", p.extruder_cali_manual_mode, w); #else if (j.contains("extruder_cali_manual_mode")) { w.emplace_back("'extruder_cali_manual_mode' present but ABI < 0x020400; " "skipping (rebuild plugin_runner with newer --abi)"); } #endif set_bool (j, "task_ext_change_assist", p.task_ext_change_assist, w); set_bool (j, "try_emmc_print", p.try_emmc_print, w); #if ABI_VERSION >= 0x020701 set_string(j, "svc_context", p.svc_context, w); #else if (j.contains("svc_context")) { w.emplace_back("'svc_context' present but ABI < 0x020701; " "skipping (rebuild plugin_runner with newer --abi)"); } #endif #if ABI_VERSION >= 0x020801 set_string(j, "slicer_uid", p.slicer_uid, w); #else if (j.contains("slicer_uid")) { w.emplace_back("'slicer_uid' present but ABI < 0x020801; " "skipping (rebuild plugin_runner with newer --abi)"); } #endif #if ABI_VERSION >= 0x020802 set_string(j, "queue_plate_id", p.queue_plate_id, w); #else if (j.contains("queue_plate_id")) { w.emplace_back("'queue_plate_id' present but ABI < 0x020802; " "skipping (rebuild plugin_runner with newer --abi)"); } #endif } } // namespace void load_print_params_from_json(const std::string& json_path, BBL::PrintParams& out, std::vector& warnings) { std::ifstream ifs(json_path); if (!ifs) { throw std::runtime_error("cannot open " + json_path + " for reading"); } json j; try { ifs >> j; } catch (const std::exception& e) { throw std::runtime_error("failed to parse " + json_path + ": " + e.what()); } if (!j.is_object()) { throw std::runtime_error(json_path + " must contain a JSON object at the top level"); } warn_unknown(j, warnings); apply_overlay(j, out, warnings); } } // namespace obn::plugin_runner