Compare commits

..

14 Commits

Author SHA1 Message Date
Ian Chua
6345d57512 fix: use get_current_printer_agent_id 2026-08-06 16:26:39 +08:00
Ian Chua
159e577543 feat: Isolate devices across different printer agents 2026-08-06 16:11:44 +08:00
Ian Chua
b2e05d0683 Merge remote-tracking branch 'origin/refactor/access-codes' into refactor/printer-agent-interface 2026-08-05 20:37:57 +08:00
Ian Chua
ae27a09ffe Merge remote-tracking branch 'origin/refactor/access-codes' into refactor/printer-agent-interface 2026-08-05 20:02:23 +08:00
Ian Chua
cd33f589dc Merge branch 'main' into refactor/printer-agent-interface 2026-08-05 20:02:02 +08:00
Ian Chua
f3f44bffcb Merge branch 'feat/printer-agent-ui' of https://github.com/OrcaSlicer/OrcaSlicer into refactor/printer-agent-interface 2026-08-05 13:20:18 +08:00
Ian Chua
2d3e911efa Merge branch 'main' into refactor/printer-agent-interface 2026-08-05 13:16:47 +08:00
Ian Chua
56236f56a8 Add unsupported-command feedback to the device UI 2026-08-04 21:26:56 +08:00
Ian Chua
df5a08517a Keep printer-agent error codes with the interface 2026-08-04 19:44:39 +08:00
Andrew
5d953f915a Keep Bambu AMS dialect out of the agent waist
M620 is Bambu firmware dialect, not a
neutral command. Composing it in
MachineObject let non-Bambu agents
(Moonraker/Klipper) forward it and
report success on firmware that
cannot run it.

Agents now own the dialect: the
default refusal on IPrinterAgent
returns not-supported so the UI
can say so; BBLPrinterAgent keeps
the byte-identical composition.
2026-08-04 18:12:20 +08:00
Andrew
dd2cb92685 Gate agent mode behind use_printer_agents toggle
Replace per-printer auto-activation
(is_current_printer_agent_plugin)
with a global experimental AppConfig
toggle, default off: legacy
print-host behavior is unchanged
until the user opts in. The toggle
drives device-tab routing, print
button defaults, connect-button
visibility and sidebar layout, and
dedups machine-select dialog opens.
2026-08-04 18:12:20 +08:00
Andrew
b2f08c3ff8 Reset device selection on agent swap or unload (#124)
set_live_printer_agent centralizes
the swap: deselect the machine,
clear stale sidebar state and the
previous agent's Other Devices, then
install the new agent (or null when
its provider vanished). Plugin
load/unload callbacks refresh the
dropdown and re-run agent selection.
load_last_machine no longer falls
back to the first available machine.
2026-08-04 18:12:19 +08:00
Andrew
75a2460649 Replace fake-enum printer agent dropdown (#121)
A dedicated PrinterAgentChoice field
reads rows straight from the live
agent registry and stores the agent
id string, replacing the fake-coEnum
index mapping. The field moves to
TabPrinter and registers with the
searcher so UnsavedChanges renders
it; the PhysicalPrinterDialog copy
and its update hook are removed
(#125). switch_printer_agent now
resolves ids via
resolve_printer_agent_id.
2026-08-04 18:12:19 +08:00
Ian Chua
01493d4e3a Add developer flag for printer agents 2026-08-04 18:12:19 +08:00
14 changed files with 276 additions and 41 deletions

View File

@@ -853,6 +853,10 @@ std::string AppConfig::load()
local_machine.dev_ip = p["dev_ip"].get<std::string>(); local_machine.dev_ip = p["dev_ip"].get<std::string>();
if (p.contains("printer_type")) if (p.contains("printer_type"))
local_machine.printer_type = p["printer_type"].get<std::string>(); local_machine.printer_type = p["printer_type"].get<std::string>();
if (p.contains("printer_agent_id"))
local_machine.printer_agent_id = p["printer_agent_id"].get<std::string>();
if (p.contains("access_code"))
local_machine.access_code = p["access_code"].get<std::string>();
m_local_machines[local_machine.dev_id] = local_machine; m_local_machines[local_machine.dev_id] = local_machine;
} }
} else { } else {
@@ -1065,6 +1069,8 @@ void AppConfig::save()
m_json["dev_name"] = local_machine.second.dev_name; m_json["dev_name"] = local_machine.second.dev_name;
m_json["dev_ip"] = local_machine.second.dev_ip; m_json["dev_ip"] = local_machine.second.dev_ip;
m_json["printer_type"] = local_machine.second.printer_type; m_json["printer_type"] = local_machine.second.printer_type;
m_json["printer_agent_id"] = local_machine.second.printer_agent_id;
m_json["access_code"] = local_machine.second.access_code;
j["local_machines"][local_machine.first] = m_json; j["local_machines"][local_machine.first] = m_json;
} }

View File

@@ -61,10 +61,19 @@ struct BBLocalMachine
std::string dev_ip; std::string dev_ip;
std::string dev_id; /* serial number */ std::string dev_id; /* serial number */
std::string printer_type; /* model_id */ std::string printer_type; /* model_id */
std::string printer_agent_id; /* id of the IPrinterAgent that discovered/bound this device, e.g. "bbl"; empty for entries persisted before this field existed */
// Access code, scoped to printer_agent_id above - so a code saved while bound under one
// printer agent isn't treated as valid for a different, independent agent talking to the
// same physical dev_id. Empty for entries persisted before this field existed; those fall
// back to the legacy flat "access_code"/"user_access_code" AppConfig sections (BBL-only,
// since BBL was the only agent when they were saved) - see
// get_access_code_with_legacy_fallback() in DevManager.cpp.
std::string access_code;
bool operator==(const BBLocalMachine& other) const bool operator==(const BBLocalMachine& other) const
{ {
return dev_name == other.dev_name && dev_ip == other.dev_ip && dev_id == other.dev_id && printer_type == other.printer_type; return dev_name == other.dev_name && dev_ip == other.dev_ip && dev_id == other.dev_id && printer_type == other.printer_type &&
printer_agent_id == other.printer_agent_id && access_code == other.access_code;
} }
bool operator!=(const BBLocalMachine& other) const { return !operator==(other); } bool operator!=(const BBLocalMachine& other) const { return !operator==(other); }
}; };

View File

@@ -10,21 +10,37 @@
#include "slic3r/GUI/I18N.hpp" #include "slic3r/GUI/I18N.hpp"
#include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/Plater.hpp"
#include "slic3r/Utils/NetworkAgentFactory.hpp"
#include "libslic3r/Time.hpp" #include "libslic3r/Time.hpp"
using namespace nlohmann; using namespace nlohmann;
namespace { namespace {
// Orca: access_code and user_access_code used to be separate AppConfig keys before the two // Orca: access_code lives on BBLocalMachine::access_code (keyed by dev_id via
// fields were merged; fall back to the legacy key so existing users' saved codes aren't lost. // get_local_machines(), scoped by the record's own printer_agent_id field) - so binding a
std::string get_access_code_with_legacy_fallback(Slic3r::AppConfig* config, const std::string& dev_id) // printer under one agent doesn't silently appear as already-bound under a different,
// independent agent. This only covers LAN devices (BBLocalMachine's own scope); access_code
// and user_access_code used to be the only, flat dev_id-only AppConfig keys before
// BBLocalMachine::access_code existed, and codes saved back then are still stored flat (no
// agent association at all). Since BBL was the only agent that existed at the time, honor
// those flat legacy keys as implicitly BBL's - but only for the BBL agent, so they aren't
// leaked to other agents that never bound the device themselves.
std::string get_access_code_with_legacy_fallback(Slic3r::AppConfig* config, const std::string& dev_id, const std::string& agent_id)
{ {
const auto& machines = config->get_local_machines();
auto it = machines.find(dev_id);
if (it != machines.end() && it->second.printer_agent_id == agent_id && !it->second.access_code.empty())
return it->second.access_code;
if (agent_id == Slic3r::BBL_PRINTER_AGENT_ID || agent_id.empty()) {
std::string code = config->get("access_code", dev_id); std::string code = config->get("access_code", dev_id);
if (code.empty()) if (code.empty())
code = config->get("user_access_code", dev_id); code = config->get("user_access_code", dev_id);
return code; return code;
} }
return "";
}
} }
namespace Slic3r namespace Slic3r
@@ -55,12 +71,13 @@ namespace Slic3r
continue; continue;
MachineObject* obj = new MachineObject(this, m_agent, m.dev_name, m.dev_id, m.dev_ip); MachineObject* obj = new MachineObject(this, m_agent, m.dev_name, m.dev_id, m.dev_ip);
obj->printer_type = m.printer_type; obj->printer_type = m.printer_type;
obj->printer_agent_id = m.printer_agent_id;
obj->dev_connection_type = "lan"; obj->dev_connection_type = "lan";
obj->bind_state = "free"; obj->bind_state = "free";
obj->bind_sec_link = "secure"; obj->bind_sec_link = "secure";
obj->m_is_online = true; obj->m_is_online = true;
obj->last_alive = Slic3r::Utils::get_current_time_utc(); obj->last_alive = Slic3r::Utils::get_current_time_utc();
obj->set_access_code(get_access_code_with_legacy_fallback(config, m.dev_id), false); obj->set_access_code(get_access_code_with_legacy_fallback(config, m.dev_id, obj->printer_agent_id), false);
if (obj->has_access_right()) { if (obj->has_access_right()) {
localMachineList.insert(std::make_pair(m.dev_id, obj)); localMachineList.insert(std::make_pair(m.dev_id, obj));
} else { } else {
@@ -81,6 +98,8 @@ namespace Slic3r
local_machine.dev_name = m.get_dev_name(); local_machine.dev_name = m.get_dev_name();
local_machine.dev_ip = m.get_dev_ip(); local_machine.dev_ip = m.get_dev_ip();
local_machine.printer_type = m.printer_type; local_machine.printer_type = m.printer_type;
local_machine.printer_agent_id = m.printer_agent_id;
local_machine.access_code = m.get_access_code();
config->update_local_machine(local_machine); config->update_local_machine(local_machine);
} }
} else { } else {
@@ -143,6 +162,14 @@ namespace Slic3r
} }
} }
std::string DeviceManager::get_current_printer_agent_id() const
{
if (!m_agent)
return "";
auto printer_agent = m_agent->get_printer_agent();
return printer_agent ? printer_agent->get_agent_info().id : "";
}
void DeviceManager::EnableMultiMachine(bool enable) void DeviceManager::EnableMultiMachine(bool enable)
{ {
m_agent->enable_multi_machine(enable); m_agent->enable_multi_machine(enable);
@@ -339,6 +366,7 @@ namespace Slic3r
/* insert a new machine */ /* insert a new machine */
obj = new MachineObject(this, m_agent, dev_name, dev_id, dev_ip); obj = new MachineObject(this, m_agent, dev_name, dev_id, dev_ip);
obj->printer_type = _parse_printer_type(printer_type_str); obj->printer_type = _parse_printer_type(printer_type_str);
obj->printer_agent_id = get_current_printer_agent_id();
obj->wifi_signal = printer_signal; obj->wifi_signal = printer_signal;
obj->dev_connection_type = connect_type; obj->dev_connection_type = connect_type;
obj->bind_state = bind_state; obj->bind_state = bind_state;
@@ -350,7 +378,7 @@ namespace Slic3r
//load access code //load access code
AppConfig* config = Slic3r::GUI::wxGetApp().app_config; AppConfig* config = Slic3r::GUI::wxGetApp().app_config;
if (config) { if (config) {
obj->set_access_code(get_access_code_with_legacy_fallback(config, dev_id), false); obj->set_access_code(get_access_code_with_legacy_fallback(config, dev_id, obj->printer_agent_id), false);
} }
localMachineList.insert(std::make_pair(dev_id, obj)); localMachineList.insert(std::make_pair(dev_id, obj));
@@ -379,6 +407,7 @@ namespace Slic3r
obj = it->second; obj = it->second;
} else { } else {
obj = new MachineObject(this, m_agent, machine.dev_name, machine.dev_id, machine.dev_ip); obj = new MachineObject(this, m_agent, machine.dev_name, machine.dev_id, machine.dev_ip);
obj->printer_agent_id = get_current_printer_agent_id();
localMachineList.insert(std::make_pair(machine.dev_id, obj)); localMachineList.insert(std::make_pair(machine.dev_id, obj));
} }
if (machine.printer_type.empty()) if (machine.printer_type.empty())
@@ -505,16 +534,26 @@ namespace Slic3r
OnSelectedMachineChanged(previous_selected_machine, selected_machine); OnSelectedMachineChanged(previous_selected_machine, selected_machine);
} }
void DeviceManager::clear_other_devices() void DeviceManager::clear_other_devices(const std::string& target_agent_id)
{ {
// why: on agent swap, keep "My Devices" but drop the transient "Other Devices" // why: on agent swap, keep "My Devices" but drop the transient "Other Devices"
// Those belong to the previous agent's network scan; the new agent's start_discovery re-populates its own. // Those belong to the previous agent's network scan; the new agent's start_discovery re-populates its own.
//
// Also drop "My Devices" stamped by a different agent than the one we're swapping to
// (target_agent_id, passed by the caller since the live agent hasn't been repointed yet
// at this point): otherwise a device first discovered under agent A survives every swap
// with a stale printer_agent_id, stays hidden from every agent's filtered list, and only
// gets re-tagged if something happens to delete and re-create it (e.g. account logout).
// Dropping it here instead lets the new agent's start_discovery re-insert and re-stamp it
// like any other fresh device.
const auto my = get_my_machine_list(); const auto my = get_my_machine_list();
for (auto it = localMachineList.begin(); it != localMachineList.end();) for (auto it = localMachineList.begin(); it != localMachineList.end();)
{ {
if (my.find(it->first) == my.end()) const bool is_my_device = my.find(it->first) != my.end();
const bool agent_mismatch = !target_agent_id.empty() && it->second &&
it->second->printer_agent_id != target_agent_id;
if (!is_my_device || agent_mismatch)
{ {
// not a "My Device" -> an "Other Device"
delete it->second; delete it->second;
it = localMachineList.erase(it); it = localMachineList.erase(it);
} }
@@ -697,13 +736,16 @@ namespace Slic3r
m_agent->add_subscribe(subscribe_list_cache); m_agent->add_subscribe(subscribe_list_cache);
} }
std::map<std::string, MachineObject*> DeviceManager::get_my_machine_list() std::map<std::string, MachineObject*> DeviceManager::get_my_machine_list(const std::string& agent_id)
{ {
std::map<std::string, MachineObject*> result; std::map<std::string, MachineObject*> result;
for (auto it = userMachineList.begin(); it != userMachineList.end(); it++) for (auto it = userMachineList.begin(); it != userMachineList.end(); it++)
{ {
if (it->second && !it->second->is_lan_mode_printer()) if (!it->second || (!agent_id.empty() && it->second->printer_agent_id != agent_id))
continue;
if (!it->second->is_lan_mode_printer())
{ {
result.insert(std::make_pair(it->first, it->second)); result.insert(std::make_pair(it->first, it->second));
} }
@@ -711,7 +753,10 @@ namespace Slic3r
for (auto it = localMachineList.begin(); it != localMachineList.end(); it++) for (auto it = localMachineList.begin(); it != localMachineList.end(); it++)
{ {
if (it->second && it->second->has_access_right() && it->second->is_avaliable() && it->second->is_lan_mode_printer()) if (!it->second || (!agent_id.empty() && it->second->printer_agent_id != agent_id))
continue;
if (it->second->has_access_right() && it->second->is_avaliable() && it->second->is_lan_mode_printer())
{ {
// remove redundant in userMachineList // remove redundant in userMachineList
if (result.find(it->first) == result.end()) if (result.find(it->first) == result.end())
@@ -723,12 +768,15 @@ namespace Slic3r
return result; return result;
} }
std::map<std::string, MachineObject*> DeviceManager::get_my_cloud_machine_list() std::map<std::string, MachineObject*> DeviceManager::get_my_cloud_machine_list(const std::string& agent_id)
{ {
std::map<std::string, MachineObject*> result; std::map<std::string, MachineObject*> result;
for (auto it = userMachineList.begin(); it != userMachineList.end(); it++) for (auto it = userMachineList.begin(); it != userMachineList.end(); it++)
{ {
if (it->second && !it->second->is_lan_mode_printer()) { result.emplace(*it); } if (!it->second || (!agent_id.empty() && it->second->printer_agent_id != agent_id))
continue;
if (!it->second->is_lan_mode_printer()) { result.emplace(*it); }
} }
return result; return result;
} }
@@ -801,6 +849,7 @@ namespace Slic3r
else else
{ {
obj = new MachineObject(this, m_agent, "", "", ""); obj = new MachineObject(this, m_agent, "", "", "");
obj->printer_agent_id = get_current_printer_agent_id();
if (m_agent) if (m_agent)
{ {
obj->set_bind_status(m_agent->get_user_name(provider)); obj->set_bind_status(m_agent->get_user_name(provider));

View File

@@ -74,7 +74,10 @@ public:
void erase_user_machine(std::string dev_id) { userMachineList.erase(dev_id); } void erase_user_machine(std::string dev_id) { userMachineList.erase(dev_id); }
void clean_user_info(bool keep_local_selection = false); void clean_user_info(bool keep_local_selection = false);
void clear_other_devices(); // target_agent_id: id of the agent being swapped to (empty = no agent-mismatch check,
// just the original "drop Other Devices" behavior). Pass the incoming agent's id, not the
// live one - this runs before the live agent is repointed.
void clear_other_devices(const std::string& target_agent_id = "");
void load_last_machine(); void load_last_machine();
void update_user_machine_list_info(const std::string& provider); void update_user_machine_list_info(const std::string& provider);
@@ -90,10 +93,15 @@ public:
/* my machine*/ /* my machine*/
MachineObject* get_my_machine(std::string dev_id); MachineObject* get_my_machine(std::string dev_id);
std::map<std::string, MachineObject*> get_my_machine_list(); std::map<std::string, MachineObject*> get_my_machine_list(const std::string& agent_id = "");
std::map<std::string, MachineObject*> get_my_cloud_machine_list(); std::map<std::string, MachineObject*> get_my_cloud_machine_list(const std::string& agent_id = "");
void modify_device_name(std::string dev_id, std::string dev_name, const std::string& provider); void modify_device_name(std::string dev_id, std::string dev_name, const std::string& provider);
// id of the currently live IPrinterAgent (IPrinterAgent::get_agent_info().id), or empty if
// m_agent has no printer agent set yet. Pass to get_my_machine_list()/get_my_cloud_machine_list()
// to scope results to the active agent.
std::string get_current_printer_agent_id() const;
/* create machine or update machine properties */ /* create machine or update machine properties */
void on_machine_alive(std::string json_str); void on_machine_alive(std::string json_str);
int query_bind_status(std::string& msg, const std::string& provider); int query_bind_status(std::string& msg, const std::string& provider);

View File

@@ -3,6 +3,7 @@
#include "libslic3r/Time.hpp" #include "libslic3r/Time.hpp"
#include "libslic3r/Thread.hpp" #include "libslic3r/Thread.hpp"
#include "slic3r/Utils/NetworkAgent.hpp" #include "slic3r/Utils/NetworkAgent.hpp"
#include "slic3r/Utils/NetworkAgentFactory.hpp"
#include "GuiColor.hpp" #include "GuiColor.hpp"
#include "GUI_App.hpp" #include "GUI_App.hpp"
@@ -458,11 +459,41 @@ void MachineObject::set_access_code(std::string code, bool only_refresh)
if (only_refresh) { if (only_refresh) {
AppConfig* config = GUI::wxGetApp().app_config; AppConfig* config = GUI::wxGetApp().app_config;
if (config) { if (config) {
if (is_lan_mode_printer()) {
// why: LAN codes are scoped via BBLocalMachine::access_code, keyed by dev_id and
// scoped by that record's own printer_agent_id field - see the matching comment
// on get_access_code_with_legacy_fallback() in DevManager.cpp - so binding this
// device under one printer agent doesn't silently read as already-bound under a
// different, independent one. Cloud devices (the else branch below) aren't
// scoped this way: they're never recalled from a stale local cache across a
// session boundary, since parse_user_print_info() always overwrites their code
// fresh from the cloud API's current response, so there's no cross-agent leakage
// risk to guard against there.
if (!code.empty()) { if (!code.empty()) {
GUI::wxGetApp().app_config->set_str("access_code", get_dev_id(), code);
DeviceManager::update_local_machine(*this); DeviceManager::update_local_machine(*this);
} else { } else {
GUI::wxGetApp().app_config->erase("access_code", get_dev_id()); // Only patch an existing record's code - don't persist a brand-new
// never-bound entry just because set_access_code("") was called on it.
const auto& machines = config->get_local_machines();
auto it = machines.find(get_dev_id());
if (it != machines.end()) {
BBLocalMachine local_machine = it->second;
local_machine.access_code = "";
config->update_local_machine(local_machine);
}
// Also clear the pre-scoping flat legacy key when unbinding under BBL, so an
// old BBL-era code can't silently "re-bind" this device again via
// get_access_code_with_legacy_fallback()'s legacy fallback.
if (printer_agent_id == BBL_PRINTER_AGENT_ID || printer_agent_id.empty()) {
config->erase("access_code", get_dev_id());
config->erase("user_access_code", get_dev_id());
}
}
} else {
if (!code.empty())
config->set_str("access_code", get_dev_id(), code);
else
config->erase("access_code", get_dev_id());
} }
} }
} }
@@ -1700,9 +1731,11 @@ int MachineObject::command_ams_user_settings(bool start_read_opt, bool tray_read
int MachineObject::command_ams_calibrate(int ams_id) int MachineObject::command_ams_calibrate(int ams_id)
{ {
std::string gcode_cmd = (boost::format("M620 C%1% \n") % ams_id).str(); if (!m_agent) return -1;
BOOST_LOG_TRIVIAL(trace) << "ams_debug: gcode_cmd" << gcode_cmd; int rtn = m_agent->command_ams_calibrate(get_dev_id(), ams_id, MachineObject::m_sequence_id++, is_lan_mode_printer());
return this->publish_gcode(gcode_cmd); if (rtn == ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED || rtn == ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE)
show_unsupported_dlg(rtn);
return rtn;
} }
int MachineObject::command_ams_filament_settings(int ams_id, int slot_id, std::string filament_id, std::string setting_id, std::string tray_color, std::string tray_type, int nozzle_temp_min, int nozzle_temp_max) int MachineObject::command_ams_filament_settings(int ams_id, int slot_id, std::string filament_id, std::string setting_id, std::string tray_color, std::string tray_type, int nozzle_temp_min, int nozzle_temp_max)
@@ -1740,9 +1773,11 @@ int MachineObject::command_ams_filament_settings(int ams_id, int slot_id, std::s
int MachineObject::command_ams_refresh_rfid(std::string tray_id) int MachineObject::command_ams_refresh_rfid(std::string tray_id)
{ {
std::string gcode_cmd = (boost::format("M620 R%1% \n") % tray_id).str(); if (!m_agent) return -1;
BOOST_LOG_TRIVIAL(trace) << "ams_debug: gcode_cmd" << gcode_cmd; int rtn = m_agent->command_ams_refresh_rfid(get_dev_id(), tray_id, MachineObject::m_sequence_id++, is_lan_mode_printer());
return this->publish_gcode(gcode_cmd); if (rtn == ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED || rtn == ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE)
show_unsupported_dlg(rtn);
return rtn;
} }
int MachineObject::command_ams_refresh_rfid2(int ams_id, int slot_id) int MachineObject::command_ams_refresh_rfid2(int ams_id, int slot_id)
@@ -1758,9 +1793,11 @@ int MachineObject::command_ams_refresh_rfid2(int ams_id, int slot_id)
int MachineObject::command_ams_select_tray(std::string tray_id) int MachineObject::command_ams_select_tray(std::string tray_id)
{ {
std::string gcode_cmd = (boost::format("M620 P%1% \n") % tray_id).str(); if (!m_agent) return -1;
BOOST_LOG_TRIVIAL(trace) << "ams_debug: gcode_cmd" << gcode_cmd; int rtn = m_agent->command_ams_select_tray(get_dev_id(), tray_id, MachineObject::m_sequence_id++, is_lan_mode_printer());
return this->publish_gcode(gcode_cmd); if (rtn == ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED || rtn == ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE)
show_unsupported_dlg(rtn);
return rtn;
} }
int MachineObject::command_ams_control(std::string action) int MachineObject::command_ams_control(std::string action)

View File

@@ -229,6 +229,16 @@ public:
//PRINTER_TYPE printer_type = PRINTER_3DPrinter_UKNOWN; //PRINTER_TYPE printer_type = PRINTER_3DPrinter_UKNOWN;
std::string printer_type; /* model_id */ std::string printer_type; /* model_id */
// id of the IPrinterAgent that was used to discover or bind this device (IPrinterAgent::get_agent_info().id,
// e.g. "bbl"), stamped at creation time — not derived from get_agent(), since m_agent is a single
// process-wide NetworkAgent shared by every MachineObject and gets repointed on agent swap
// (see DeviceManager::set_agent()), so it can't tell which agent originally found this device.
// We persist this as well so that when the printer agent is swapped, we don't show unrelated devices,
// e.g. if the current printer agent is elegoo, we shouldn't show printers connected by BBL printer agent
// under local machines.
std::string printer_agent_id;
std::string get_show_printer_type() const; std::string get_show_printer_type() const;
PrinterSeries get_printer_series() const; PrinterSeries get_printer_series() const;
PrinterArch get_printer_arch() const; PrinterArch get_printer_arch() const;

View File

@@ -3937,7 +3937,13 @@ void GUI_App::set_live_printer_agent(std::shared_ptr<IPrinterAgent> agent)
m_agent->set_user_selected_machine(""); m_agent->set_user_selected_machine("");
// note: belt-and-suspenders (precedent: DeviceManagerRefresher::on_timer) // note: belt-and-suspenders (precedent: DeviceManagerRefresher::on_timer)
dev->OnSelectedMachineLost(); // why: clear stale sidebar sync-status / AMS dev->OnSelectedMachineLost(); // why: clear stale sidebar sync-status / AMS
dev->clear_other_devices(); // why: drop stale LAN discoveries; keep My Devices // why: drop stale LAN discoveries; keep My Devices, but only those belonging to the
// agent we're about to swap to, so a device stamped by the outgoing agent doesn't
// linger hidden - the new agent's start_discovery re-inserts and re-stamps it fresh.
// agent is null when clearing the live agent entirely (e.g. plugin unload); there's no
// target to filter against then, so fall back to the original "keep all My Devices"
// behavior rather than guessing.
dev->clear_other_devices(agent ? agent->get_agent_info().id : std::string());
} }
m_agent->set_printer_agent(agent); m_agent->set_printer_agent(agent);

View File

@@ -3913,7 +3913,7 @@ _collect_sorted_machines(Slic3r::DeviceManager* dev_manager,
}; };
// collect from user machine list // collect from user machine list
const auto& user_machine_list = dev_manager->get_my_machine_list();// user machine list const auto& user_machine_list = dev_manager->get_my_machine_list(dev_manager->get_current_printer_agent_id());// user machine list
for (const auto& elem : user_machine_list) for (const auto& elem : user_machine_list)
{ {
MachineObject* mobj = elem.second; MachineObject* mobj = elem.second;

View File

@@ -501,6 +501,7 @@ void SelectMachinePopup::update_other_devices()
DeviceManager* dev = wxGetApp().getDeviceManager(); DeviceManager* dev = wxGetApp().getDeviceManager();
if (!dev) return; if (!dev) return;
m_free_machine_list = dev->get_local_machinelist(); m_free_machine_list = dev->get_local_machinelist();
const std::string current_agent_id = dev->get_current_printer_agent_id();
BOOST_LOG_TRIVIAL(trace) << "SelectMachinePopup update_other_devices start"; BOOST_LOG_TRIVIAL(trace) << "SelectMachinePopup update_other_devices start";
this->Freeze(); this->Freeze();
@@ -512,6 +513,10 @@ void SelectMachinePopup::update_other_devices()
/* do not show printer bind state is empty */ /* do not show printer bind state is empty */
if (!mobj->is_avaliable()) continue; if (!mobj->is_avaliable()) continue;
/* do not show devices discovered/bound by a different printer agent */
if (mobj->printer_agent_id != current_agent_id)
continue;
if (!wxGetApp().is_user_login(wxGetApp().get_printer_cloud_provider()) && !mobj->is_lan_mode_printer()) if (!wxGetApp().is_user_login(wxGetApp().get_printer_cloud_provider()) && !mobj->is_lan_mode_printer())
continue; continue;
@@ -634,7 +639,7 @@ void SelectMachinePopup::update_user_devices()
} }
m_bind_machine_list.clear(); m_bind_machine_list.clear();
m_bind_machine_list = dev->get_my_machine_list(); m_bind_machine_list = dev->get_my_machine_list(dev->get_current_printer_agent_id());
//sort list //sort list
std::vector<std::pair<std::string, MachineObject*>> user_machine_list; std::vector<std::pair<std::string, MachineObject*>> user_machine_list;

View File

@@ -2,7 +2,9 @@
#include "BBLNetworkPlugin.hpp" #include "BBLNetworkPlugin.hpp"
#include "NetworkAgentFactory.hpp" #include "NetworkAgentFactory.hpp"
#include <boost/format.hpp>
#include <boost/log/trivial.hpp> #include <boost/log/trivial.hpp>
#include <nlohmann/json.hpp>
namespace Slic3r { namespace Slic3r {
@@ -20,6 +22,65 @@ void BBLPrinterAgent::set_cloud_agent(std::shared_ptr<ICloudServiceAgent> cloud)
// Communication // Communication
// ============================================================================ // ============================================================================
std::string BBLPrinterAgent::ams_refresh_rfid_gcode(const std::string& tray_id)
{
return (boost::format("M620 R%1% \n") % tray_id).str();
}
std::string BBLPrinterAgent::ams_calibrate_gcode(int ams_id)
{
return (boost::format("M620 C%1% \n") % ams_id).str();
}
std::string BBLPrinterAgent::ams_select_tray_gcode(const std::string& tray_id)
{
return (boost::format("M620 P%1% \n") % tray_id).str();
}
int BBLPrinterAgent::command_ams_refresh_rfid(std::string dev_id, std::string tray_id, int sequence_id, bool lan_mode)
{
const std::string gcode = ams_refresh_rfid_gcode(tray_id);
BOOST_LOG_TRIVIAL(trace) << "ams_debug: gcode_cmd" << gcode;
nlohmann::json j;
j["print"]["command"] = "gcode_line";
j["print"]["param"] = gcode;
j["print"]["sequence_id"] = std::to_string(sequence_id);
return publish(dev_id, j, lan_mode);
}
int BBLPrinterAgent::command_ams_calibrate(std::string dev_id, int ams_id, int sequence_id, bool lan_mode)
{
const std::string gcode = ams_calibrate_gcode(ams_id);
BOOST_LOG_TRIVIAL(trace) << "ams_debug: gcode_cmd" << gcode;
nlohmann::json j;
j["print"]["command"] = "gcode_line";
j["print"]["param"] = gcode;
j["print"]["sequence_id"] = std::to_string(sequence_id);
return publish(dev_id, j, lan_mode);
}
int BBLPrinterAgent::command_ams_select_tray(std::string dev_id, std::string tray_id, int sequence_id, bool lan_mode)
{
const std::string gcode = ams_select_tray_gcode(tray_id);
BOOST_LOG_TRIVIAL(trace) << "ams_debug: gcode_cmd" << gcode;
nlohmann::json j;
j["print"]["command"] = "gcode_line";
j["print"]["param"] = gcode;
j["print"]["sequence_id"] = std::to_string(sequence_id);
return publish(dev_id, j, lan_mode);
}
int BBLPrinterAgent::publish(const std::string& dev_id, const nlohmann::json& j, bool lan_mode)
{
const int rtn = lan_mode ? send_message_to_printer(dev_id, j.dump(), 0, 0) : send_message(dev_id, j.dump(), 0, 0);
if (rtn == 0) {
BOOST_LOG_TRIVIAL(info) << "publish_json: " << j.dump() << " code: " << rtn;
} else {
BOOST_LOG_TRIVIAL(error) << "publish_json: " << j.dump() << " code: " << rtn;
}
return rtn;
}
int BBLPrinterAgent::send_message(std::string dev_id, std::string json_str, int qos, int flag) int BBLPrinterAgent::send_message(std::string dev_id, std::string json_str, int qos, int flag)
{ {
auto& plugin = BBLNetworkPlugin::instance(); auto& plugin = BBLNetworkPlugin::instance();

View File

@@ -5,6 +5,7 @@
#include "ICloudServiceAgent.hpp" #include "ICloudServiceAgent.hpp"
#include <string> #include <string>
#include <memory> #include <memory>
#include <nlohmann/json.hpp>
namespace Slic3r { namespace Slic3r {
@@ -28,6 +29,12 @@ public:
// Communication // Communication
int send_message(std::string dev_id, std::string json_str, int qos, int flag) override; int send_message(std::string dev_id, std::string json_str, int qos, int flag) override;
static std::string ams_refresh_rfid_gcode(const std::string& tray_id);
static std::string ams_calibrate_gcode(int ams_id);
static std::string ams_select_tray_gcode(const std::string& tray_id);
int command_ams_refresh_rfid(std::string dev_id, std::string tray_id, int sequence_id, bool lan_mode) override;
int command_ams_calibrate(std::string dev_id, int ams_id, int sequence_id, bool lan_mode) override;
int command_ams_select_tray(std::string dev_id, std::string tray_id, int sequence_id, bool lan_mode) override;
int connect_printer(std::string dev_id, std::string dev_ip, std::string username, std::string password, bool use_ssl) override; int connect_printer(std::string dev_id, std::string dev_ip, std::string username, std::string password, bool use_ssl) override;
int disconnect_printer() override; int disconnect_printer() override;
int send_message_to_printer(std::string dev_id, std::string json_str, int qos, int flag) override; int send_message_to_printer(std::string dev_id, std::string json_str, int qos, int flag) override;
@@ -85,6 +92,9 @@ public:
FilamentSyncMode get_filament_sync_mode() const override; FilamentSyncMode get_filament_sync_mode() const override;
private: private:
// why: the lan/cloud DECISION stays machine-side; keep this mechanical branch in sync with publish_json.
int publish(const std::string& dev_id, const nlohmann::json& j, bool lan_mode);
std::shared_ptr<ICloudServiceAgent> m_cloud_agent; std::shared_ptr<ICloudServiceAgent> m_cloud_agent;
}; };

View File

@@ -84,6 +84,16 @@ public:
*/ */
virtual int send_message(std::string dev_id, std::string json_str, int qos, int flag) = 0; virtual int send_message(std::string dev_id, std::string json_str, int qos, int flag) = 0;
// why: gcode is firmware dialect, not a waist concept - commands whose body is Bambu-dialect
// gcode live on the agent that speaks it; the default is an honest refusal that MachineObject's
// publish funnel turns into a dialog.
virtual int command_ams_refresh_rfid(std::string, std::string, int, bool)
{ return ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED; }
virtual int command_ams_calibrate(std::string, int, int, bool)
{ return ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED; }
virtual int command_ams_select_tray(std::string, std::string, int, bool)
{ return ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED; }
/** /**
* Establish a direct LAN connection to a printer. * Establish a direct LAN connection to a printer.
*/ */

View File

@@ -767,6 +767,27 @@ int NetworkAgent::send_message(std::string dev_id, std::string json_str, int qos
return -1; return -1;
} }
int NetworkAgent::command_ams_refresh_rfid(std::string dev_id, std::string tray_id, int sequence_id, bool lan_mode)
{
if (m_printer_agent)
return m_printer_agent->command_ams_refresh_rfid(dev_id, tray_id, sequence_id, lan_mode);
return -1;
}
int NetworkAgent::command_ams_calibrate(std::string dev_id, int ams_id, int sequence_id, bool lan_mode)
{
if (m_printer_agent)
return m_printer_agent->command_ams_calibrate(dev_id, ams_id, sequence_id, lan_mode);
return -1;
}
int NetworkAgent::command_ams_select_tray(std::string dev_id, std::string tray_id, int sequence_id, bool lan_mode)
{
if (m_printer_agent)
return m_printer_agent->command_ams_select_tray(dev_id, tray_id, sequence_id, lan_mode);
return -1;
}
int NetworkAgent::connect_printer(std::string dev_id, std::string dev_ip, std::string username, std::string password, bool use_ssl) int NetworkAgent::connect_printer(std::string dev_id, std::string dev_ip, std::string username, std::string password, bool use_ssl)
{ {
if (m_printer_agent) if (m_printer_agent)

View File

@@ -142,6 +142,9 @@ public:
int set_on_local_message_fn(OnMessageFn fn); int set_on_local_message_fn(OnMessageFn fn);
int set_server_callback(OnServerErrFn fn); int set_server_callback(OnServerErrFn fn);
int send_message(std::string dev_id, std::string json_str, int qos, int flag); int send_message(std::string dev_id, std::string json_str, int qos, int flag);
int command_ams_refresh_rfid(std::string dev_id, std::string tray_id, int sequence_id, bool lan_mode);
int command_ams_calibrate(std::string dev_id, int ams_id, int sequence_id, bool lan_mode);
int command_ams_select_tray(std::string dev_id, std::string tray_id, int sequence_id, bool lan_mode);
int connect_printer(std::string dev_id, std::string dev_ip, std::string username, std::string password, bool use_ssl); int connect_printer(std::string dev_id, std::string dev_ip, std::string username, std::string password, bool use_ssl);
int disconnect_printer(); int disconnect_printer();
int send_message_to_printer(std::string dev_id, std::string json_str, int qos, int flag); int send_message_to_printer(std::string dev_id, std::string json_str, int qos, int flag);