Leave the AFC lane sync out of the IMEX work

MoonrakerPrinterAgent filled physical_extruder_map from AFC's per-lane
extruder_index whenever the printer's filaments were synced. IMEX does
not need it: printers carry their map in the printer profile, and IMEX
reads it from there. The sync also wrote device state into the edited
printer preset, so a sync could mark the preset modified or replace a
hand-tuned map. The two Moonraker agent files go back to upstream's
version. The sync can return separately, writing the map somewhere other
than the printer preset.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Clifford Garwood
2026-10-08 19:11:18 -04:00
co-authored by Claude Opus 5.5
parent d09850c528
commit 45932dd956
3 changed files with 1 additions and 83 deletions
+1 -3
View File
@@ -119,9 +119,7 @@ static std::vector<std::string> s_project_options {
// project_config's default [0] to clobber the preset's authored value
// (e.g. AFC-shaped [0,1,1,1,1]) during full_fff_config() merge, and the
// clobbered value then rode into saved 3mfs and back into the edited
// preset on reload. MoonrakerPrinterAgent's runtime set_key_value still
// works — it creates the option on project_config on demand without
// needing it pre-initialized here.
// preset on reload.
// Per-filament nozzle-volume choice; project-level like filament_map so the per-filament
// slot resolution survives preset switches.
"filament_volume_map",
@@ -41,7 +41,6 @@
#include <ios>
#include <functional>
#include <exception>
#include <libslic3r/Config.hpp>
#include <map>
#include <string>
#include <mutex>
@@ -51,7 +50,6 @@
#include <thread>
#include <vector>
#include <utility>
#include <wx/app.h>
namespace {
@@ -572,79 +570,6 @@ bool MoonrakerPrinterAgent::fetch_filament_info(std::string dev_id, FilamentSync
<< (max_lane_index + 1) << " lanes";
int ams_count = (max_lane_index + 4) / 4;
build_ams_payload(ams_count, max_lane_index, trays);
// If every tray reported extruder_index, auto-populate physical_extruder_map on an
// IMEX printer so IMEX PA and temperature emission use the correct physical extruder
// qualifier. AFC publishes extruder_index=0 for all AFC lanes (they share one carriage)
// and extruder_index=N for independent direct-drive tools on separate carriages.
// The write itself is gated below, on the GUI thread, where the preset can be read.
bool all_have_extruder_index = std::all_of(trays.begin(), trays.end(),
[](const AmsTrayData& t) { return t.extruder_index >= 0; });
if (all_have_extruder_index) {
std::vector<int> pem(max_lane_index + 1, 0);
for (const auto& tray : trays)
if (tray.slot_index >= 0 && tray.slot_index <= max_lane_index)
pem[tray.slot_index] = tray.extruder_index;
// Record which device this map came from. The write below targets whichever
// printer preset is being edited when the callback runs, and nothing else here
// establishes the two are the same machine: two IMEX printers of different models
// with the same logical extruder count would both pass every check below.
const std::string src_dev_id = device_info.dev_id;
wxTheApp->CallAfter([pem, src_dev_id]() {
auto* bundle = GUI::wxGetApp().preset_bundle;
if (!bundle) return;
auto& preset = bundle->printers.get_edited_preset();
auto& config = preset.config;
// Pair device to preset at callback time, on the predicate update_sync_status()
// uses. Matching against an identity captured when the device was selected would
// instead ask whether the edited preset had changed since then, and would reject
// the user who selects a machine and only then switches to its matching preset.
auto* dev_manager = GUI::wxGetApp().getDeviceManager();
MachineObject* obj = dev_manager ? dev_manager->get_selected_machine() : nullptr;
if (!obj || obj->get_dev_id() != src_dev_id) return;
const std::string preset_model = preset.get_printer_type(bundle);
if (preset_model != obj->get_show_printer_type()) {
BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent: skipping physical_extruder_map sync, the device is a "
<< obj->get_show_printer_type() << " but the edited printer preset is a "
<< preset_model;
return;
}
// Only IMEX profiles read physical_extruder_map as logical -> physical extruder.
// Elsewhere in the tree the key carries the BBL extruder-id reading, or is unused
// entirely (a single-nozzle Klipper machine), so writing the device's lane data
// there would silently mutate an unrelated setting -- and dirty the preset with
// no user action -- for every AFC user who is not running IMEX.
const auto* is_imex = config.option<ConfigOptionBool>("is_imex");
if (!is_imex || !is_imex->value) return;
// The map has one entry per LOGICAL extruder, i.e. the nozzle_diameter index
// space (see effective_physical_extruder_map() in IMEXHelpers.cpp). The device
// reports one entry per lane, which is the same index space only when the counts
// match; when they differ the lane -> logical extruder correspondence is not
// knowable here, and a wrong-length map is discarded by PrintApply anyway, so
// leave whatever the profile authored alone rather than writing a map that
// nothing will honour.
const auto* nozzles = config.option<ConfigOptionFloats>("nozzle_diameter");
if (!nozzles || nozzles->values.size() != pem.size()) {
BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent: skipping physical_extruder_map sync, device reports "
<< pem.size() << " lanes but the printer profile has "
<< (nozzles ? nozzles->values.size() : 0) << " logical extruders";
return;
}
// Write only on a real change: an unconditional set_key_value() marks the printer
// preset dirty on every device poll, so the user sees unsaved changes they never made.
const auto* current = config.option<ConfigOptionInts>("physical_extruder_map");
if (current && current->values == pem) return;
config.set_key_value("physical_extruder_map", new ConfigOptionInts(pem));
BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent: auto-populated physical_extruder_map from AFC extruder_index";
});
}
return true;
}
@@ -888,10 +813,6 @@ bool MoonrakerPrinterAgent::fetch_moonraker_filament_data(std::vector<AmsTrayDat
tray.tray_type = safe_json_string(lane_obj, "material");
tray.bed_temp = safe_json_int(lane_obj, "bed_temp");
tray.nozzle_temp = safe_json_int(lane_obj, "nozzle_temp");
// extruder_index: 0 is a valid value (AFC lanes on E0), so check contains()
// rather than relying on safe_json_int's 0-for-missing fallback.
if (lane_obj.contains("extruder_index") && lane_obj["extruder_index"].is_number())
tray.extruder_index = lane_obj["extruder_index"].get<int>();
tray.has_filament = !tray.tray_type.empty();
auto* bundle = GUI::wxGetApp().preset_bundle;
tray.tray_info_idx = bundle
@@ -88,7 +88,6 @@ protected:
// Tray data for AMS payload building
struct AmsTrayData {
int slot_index = 0; // 0-based slot index
int extruder_index = -1; // Physical extruder index from AFC extruder_index field (-1 = not provided)
bool has_filament = false;
std::string tray_type; // Material type (e.g., "PLA", "ASA")
std::string tray_color; // Raw color (#RRGGBB, 0xRRGGBB, or RRGGBBAA)