15 KiB
AMS Drying Control — Design Spec
Date: 2026-07-07
Source: Port from BambuStudio AMSDryControl feature
Reference: D:\projects\BambuStudio — match its behavior as much as possible; when in doubt, check the BambuStudio source
Branch: dev/ams-heat
Overview
Port the AMS filament drying control feature from BambuStudio into OrcaSlicer. This allows users to start, monitor, and stop AMS-based filament drying directly from the slicer UI. Currently OrcaSlicer can monitor drying state and stop drying, but cannot initiate it. This feature adds the missing start-drying command, the full drying control dialog, and the drying preset lookup infrastructure.
Target AMS models: N3F (AMS 2 Pro, max 65°C) and N3S (AMS HT, max 85°C) — the only AMS units with heating hardware.
Architecture
The feature spans three layers, matching the existing OrcaSlicer DeviceCore/ pattern:
┌─────────────────────────────────────────────────────┐
│ UI Layer │
│ AMSDryControl.hpp/.cpp (new dialog) │
│ AMSControl.cpp (hook: click → dialog) │
│ DeviceErrorDialog.cpp (stop drying on error) │
├─────────────────────────────────────────────────────┤
│ Command/Control Layer │
│ DevFilaSystemCtrl.cpp (start/stop drying) │
│ DevUtilBackend.h/.cpp (preset lookup) │
├─────────────────────────────────────────────────────┤
│ Data Model Layer │
│ DevFilaSystem.h/.cpp (enums, structs, parse) │
│ DevDefs.h (DevAmsType enum) │
└─────────────────────────────────────────────────────┘
│ Communication Layer (already exists) │
│ MachineObject::publish_json() → MQTT → printer │
└─────────────────────────────────────────────────────┘
New files (4 source + headers)
| File | Purpose |
|---|---|
src/slic3r/GUI/AMSDryControl.hpp |
AMS drying control dialog class declarations |
src/slic3r/GUI/AMSDryControl.cpp |
Dialog implementation (~1800 lines) |
src/slic3r/GUI/DeviceCore/DevFilaSystemCtrl.cpp |
CtrlAmsStartDryingHour() and CtrlAmsStopDrying() |
src/slic3r/GUI/DeviceCore/DevUtilBackend.h |
Static utility class declaring GetFilamentDryingPreset() |
src/slic3r/GUI/DeviceCore/DevUtilBackend.cpp |
Reads filament drying presets from printer config |
Modified files
| File | Changes |
|---|---|
DevFilaSystem.h |
Add drying enums/structs to DevAms; add DevFilamentDryingPreset struct; add ctrl method declarations to DevFilaSystem; add get_ams_drying_preset() to DevAmsTray |
DevFilaSystem.cpp |
Parse dry status fields in DevFilaSystemParser; implement IsSupportRemoteDry(), AmsIsDrying(), get_ams_drying_preset() |
DevDefs.h |
Add DevAmsType as a global enum |
AMSControl.cpp |
Wire humidity indicator click to open AMSDryCtrWin for N3F/N3S AMS |
DeviceErrorDialog.cpp |
Update stop-drying to use DevFilaSystem::CtrlAmsStopDrying() |
DeviceCore/CMakeLists.txt |
Register new source files |
New image assets (14)
| Asset | Purpose |
|---|---|
hum_level1_no_num_light.svg – hum_level5_no_num_light.svg |
5 humidity level icons |
dev_ams_dry_ctr_n3f_heating.png, _dehumidifying.png, _error.png, _cooling.png |
4 N3F drying state images |
dev_ams_dry_ctr_n3s_heating.png, _dehumidifying.png, _error.png, _cooling.png |
4 N3S drying state images |
dev_ams_dry_ctr_heating_icon.svg |
Animated heating indicator |
dev_ams_dry_ctr_filament_in_chamber.png |
Guide page illustration |
dev_ams_dry_ctr_enable.svg, dev_ams_dry_ctr_disable.svg |
Filament tray status icons |
Additionally, OrcaSlicer already has ams_drying.svg and ams_is_drying.svg.
Data Model
DevDefs.h — Global DevAmsType enum
Promoted from DevAms::AmsType (currently local to the class) to a global enum in DevDefs.h so DevFilamentDryingPreset and DevUtilBackend can reference it without depending on DevAms. DevAms::AmsType is updated to be a typedef for DevAmsType, and all existing references to DevAms::AmsType remain valid (it's the same type):
// DevDefs.h — global enum matching BambuStudio's DevAmsType naming
enum DevAmsType : int {
EXT_SPOOL = 0,
AMS = 1,
AMS_LITE = 2,
N3F = 3, // AMS 2 Pro
N3S = 4, // AMS HT
};
// DevFilaSystem.h — DevAms class updated:
// Replace "enum AmsType { DUMMY=0, AMS=1, AMS_LITE=2, N3F=3, N3S=4 }"
// with "using AmsType = DevAmsType;"
// Existing references to DevAms::DUMMY become DevAms::EXT_SPOOL (same value, different name).
DevAms class additions (in DevFilaSystem.h)
New enums:
| Enum | Values |
|---|---|
DryCtrlMode |
Off=0, OnTime=1, OnHumidity=2 |
DryStatus |
Off=0, Checking=1, Drying=2, Cooling=3, Stopping=4, Error=5, CannotStopHeatOutofControl=6, PrdTesting=7 |
DrySubStatus |
Off=0, Heating=1, Dehumidify=2 |
DryFanStatus |
Off=0, On=1 |
CannotDryReason |
TaskOccupied=0, InsufficientPower=1, AmsBusy=2, ConsumableAtAmsOutlet=3, InitiatingAmsDrying=4, NotSupportedIn2dMode=5, DryingInProgress=6, Upgrading=7, InsufficientPowerNeedPluginPower=8, FilamentAtAmsOutletManualUnload=10 |
New struct:
struct DrySettings {
std::string dry_filament;
int dry_temp = -1; // -1 means invalid
int dry_hour = -1; // hours
};
New getters on DevAms:
std::optional<DryStatus> GetDryStatus() conststd::optional<DrySubStatus> GetDrySubStatus() conststd::optional<DryFanStatus> GetFan1Status() conststd::optional<DryFanStatus> GetFan2Status() conststd::optional<std::vector<CannotDryReason>> GetCannotDryReason() conststd::optional<DrySettings> GetDrySettings() constbool IsSupportRemoteDry(const MachineObject* obj) constbool AmsIsDrying()
New private members: m_dry_status, m_dry_sub_status, m_dry_fan1_status, m_dry_fan2_status, m_dry_cannot_reasons, m_dry_settings — all std::optional<>.
DevFilamentDryingPreset struct (namespace scope in DevFilaSystem.h)
struct DevFilamentDryingPreset {
std::string filament_id;
std::unordered_set<DevAmsType> ams_limitations;
std::unordered_map<DevAmsType, float> filament_dev_ams_drying_time_on_idle; // hours
std::unordered_map<DevAmsType, float> filament_dev_ams_drying_temperature_on_idle;
std::unordered_map<DevAmsType, float> filament_dev_ams_drying_time_on_print; // hours
std::unordered_map<DevAmsType, float> filament_dev_ams_drying_temperature_on_print;
float filament_dev_drying_cooling_temperature;
float filament_dev_drying_softening_temperature;
float filament_dev_ams_drying_heat_distortion_temperature;
};
Populated from filament preset config keys (filament_dev_ams_drying_temperature, filament_dev_ams_drying_time, filament_dev_drying_softening_temperature, etc.).
DevAmsTray addition
std::optional<DevFilamentDryingPreset> get_ams_drying_preset() const;
Delegates to DevUtilBackend::GetFilamentDryingPreset(setting_id).
JSON parsing
DevFilaSystemParser::ParseV1_0() extended to parse the following fields from the printer's AMS status JSON:
| JSON field | DevAms member |
|---|---|
dry_status |
m_dry_status (DryStatus enum) |
dry_sub_status |
m_dry_sub_status (DrySubStatus enum) |
dry_fan1_status |
m_dry_fan1_status |
dry_fan2_status |
m_dry_fan2_status |
dry_cannot_reasons |
m_dry_cannot_reasons (vector of CannotDryReason) |
dry_settings |
m_dry_settings (DrySettings struct) |
Commands
DevFilaSystem::CtrlAmsStartDryingHour()
Publishes JSON command "ams_filament_drying" via MachineObject::publish_json():
{
"print": {
"command": "ams_filament_drying",
"sequence_id": "<seq>",
"ams_id": <int>,
"mode": 1,
"filament": "<type_string>",
"temp": <int>,
"duration": <int>,
"humidity": 0,
"rotate_tray": <bool>,
"cooling_temp": <int>,
"close_power_conflict": false
}
}
DevFilaSystem::CtrlAmsStopDrying()
Same command with mode: 0 (Off).
Existing MachineObject::command_ams_drying_stop()
Kept for backward compatibility. The error dialog will be updated to call CtrlAmsStopDrying() instead, which is the preferred path.
Backend Utility
DevUtilBackend (new, DeviceCore/DevUtilBackend.h/.cpp)
Static utility class. Only method needed for this feature:
static std::optional<DevFilamentDryingPreset> GetFilamentDryingPreset(const std::string& fila_id);
Iterates wxGetApp().preset_bundle->filaments to find the matching filament_id, then reads config keys into a DevFilamentDryingPreset. Uses a static map {"0" → N3F, "1" → N3S} for the ams_limitations string-to-enum conversion.
UI Dialog
AMSDryCtrWin (extends DPIDialog)
Three pages in a wxSimplebook:
Page 0: Main Page
Split left/right layout:
Left panel — Status display:
- Large humidity/drying state image: humidity level icon when idle; heating/dehumidifying/error animation when active
- Status label with animated heating icon ("Idle", "Drying-Heating", "Drying-Dehumidifying")
- Three stat labels: Humidity (%), Temperature (°C), Left Time (HH:MM). Left Time hidden when idle.
Right panel — Controls. Three sub-panels shown/hidden based on DryStatus and CannotDryReason:
| Sub-panel | When shown | Contents |
|---|---|---|
| Normal state | DryStatus is Off or Cooling |
Filament type combobox → Temperature input (numeric, validated to AMS limits) → Time input (hours, 1–24) → Validation warning text → Start button |
| Cannot dry | CannotDryReason is non-empty (excluding only DryingInProgress) |
Formatted reason text + Unload button (only for ConsumableAtAmsOutlet reason) |
| Drying error | DryStatus is Error |
Error message + Stop button |
| Drying active | DryStatus is Checking/Drying/Stopping |
Read-only temp/time display + Stop button |
Temperature validation rules:
- Hardware limits: N3F 45–65°C, N3S 45–85°C
- Heat distortion check: temp must not exceed
filament_dev_ams_drying_heat_distortion_temperaturewhen filament is present - Printing mode: temp must not exceed recommended drying temp when this AMS is actively feeding a print
- Time: 1–24 hours
Page 1: Guide Page
Shown after clicking Start on Page 0, before sending the command:
- Instructional text about removing heat-sensitive filament
AMSFilamentPanelshowing each tray's filament type with ✅/⚠ icons based on whether drying temp exceeds that filament's softening point- "Rotate spool when drying" checkbox
- Back and Start buttons
Page 2: Progress Page
Shown while waiting for printer to confirm drying has started:
- Animated progress bar (cycles 0–99% until printer state changes)
- Cycling status messages
- Auto-transitions back to Page 0 when printer reports drying active
Helper classes (in AMSDryControl.hpp)
FilamentItemPanel— Renders a single filament item with icon and text, with custom rounded-rectangle border paintingAMSFilamentPanel— Container for multipleFilamentItemPanelinstances, labeled with AMS nameDryingPresetstruct,DryCtrStateenum,DryCtrDevenum — Local types for tracking preset state
Dialog lifecycle
- Created on first click of the AMS humidity indicator
- Updated on each
AMSControl::parse_object()cycle viaupdate(fila_system, obj) - Auto-closes if: AMS is removed from the system, AMS no longer supports remote drying, or AMS ID becomes invalid
- Closed manually via close button or dialog destruction
- On close: stops progress timer, resets to main page, restores button states
Integration
Entry point: AMS humidity click → dialog
In AMSControl.cpp, the EVT_AMS_SHOW_HUMIDITY_TIPS handler currently shows either AmsHumidityTipPopup or uiAmsPercentHumidityDryPopup. For N3F and N3S AMS types only, replace this with opening AMSDryCtrWin:
- Lazily create
AMSDryCtrWin*member onAMSControl(likem_percent_humidity_dry_popuptoday) - Call
set_ams_id()andupdate(fila_system, obj)before showing - Show the dialog modally via
ShowModal()(matching BambuStudio behavior)
Periodic updates
AMSControl::parse_object() updates AMS state on a timer. Extend it to:
- If
m_dry_ctr_winis shown, callupdate()to refresh readings - Update the dialog's AMS ID if the user switches AMS view
Error dialog
DeviceErrorDialog.cpp line 452 calls m_obj->command_ams_drying_stop(). Update to use obj->GetFilaSystem()->CtrlAmsStopDrying(ams_id) for the correct AMS ID.
CMakeLists
src/slic3r/GUI/DeviceCore/CMakeLists.txt: addDevFilaSystemCtrl.cpp,DevUtilBackend.h,DevUtilBackend.cpp- GUI sources list: add
AMSDryControl.hpp,AMSDryControl.cpp
Testing
Manual verification
- Prerequisite: Connect to a printer with N3F or N3S AMS hardware
- Click AMS humidity indicator → verify dialog opens with correct humidity/temperature readings
- Select a filament from the combobox → verify temp/time auto-fill from preset
- Enter valid temp/time → verify Start button enables
- Enter invalid temp (e.g., 100°C for N3F) → verify warning appears and button disables
- Click Start → verify guide page shows filament tray status
- Click Start on guide page → verify progress page appears, command is sent
- Verify printer begins drying → dialog shows active drying state with countdown
- Click Stop → verify drying stops
- Test "cannot dry" states (e.g., during print, filament at outlet)
Code-level checks
- Verify
CtrlAmsStartDryingHourpublishes correct JSON structure - Verify
CtrlAmsStopDryingpublishes stop command - Verify
GetFilamentDryingPresetreturns correct values for known filament IDs - Verify dark mode rendering of all dialog pages
Constraints
- N3F/N3S only: Standard AMS and AMS Lite do not have heating hardware; the dialog is not shown for them
- Backward compatibility: Existing
command_ams_drying_stop()is preserved; new commands are additive - Cross-platform: wxWidgets UI must work on Windows, macOS, Linux
- Dark mode: Dialog must support dark mode via
wxGetApp().dark_mode()andStateColor::darkModeColorFor() - Profile compatibility: Existing profiles with
filament_dev_ams_drying_*keys (Qidi) continue to work; the feature reads the same keys - No printer-agent changes needed: All commands go through existing
publish_json()→NetworkAgentpath, which already handles MQTT for connected printers