mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-22 03:49:18 +02:00
feat(printer): support Filament Track Switch (FTS) accessory in print modal (#1162)
The FTS routes any AMS slot to either extruder, so AMS info reports
bits 8-11 = 0xE (uninitialized) and ams_extruder_map ends up empty.
The print modal's per-nozzle dropdown filter then hides every loaded
slot, leaving the user with an empty filament dropdown.
Detection: parse print.device.fila_switch from MQTT push_status into a
new FilaSwitchState dataclass on PrinterState; surface it through the
GET /printers/{id}/status response as a nullable FilaSwitchResponse.
Frontend: useFilamentMapping and FilamentMapping skip the per-extruder
filter when fila_switch.installed is true. Slots currently fed into a
track display an [L]/[R] routing badge in the dropdown so the user
can see where the FTS is currently routing them.
Tests: 4 backend unit (TestFilamentTrackSwitchDetection), 2 backend
integration (status route), 2 hook regression, 2 component regression.
This commit is contained in:
@@ -569,6 +569,62 @@ describe('computeAmsMapping - nozzle filtering', () => {
|
||||
|
||||
expect(result).toEqual([0, 4]); // Left gets AMS0-T0, Right gets AMS1-T0
|
||||
});
|
||||
|
||||
// FTS (Filament Track Switch) — when present, AMS slots aren't tied to a
|
||||
// specific extruder. The track switch routes any slot to either extruder, so
|
||||
// the per-nozzle hard filter must NOT apply. See #1162.
|
||||
it('ignores nozzle_id when FTS is installed', () => {
|
||||
// Required filament asks for nozzle 1 (left). Without FTS this would force
|
||||
// AMS 0 (which is on the left nozzle). With FTS we accept any AMS slot
|
||||
// matching by type/color since the FTS routes it to whichever extruder.
|
||||
const reqs = {
|
||||
filaments: [
|
||||
{ slot_id: 1, type: 'PETG', color: '#00FF00', used_grams: 10, nozzle_id: 1 },
|
||||
],
|
||||
};
|
||||
const status = createPrinterStatus([
|
||||
{
|
||||
id: 0, // Without FTS, this AMS would be left/extruder 1; ams_extruder_map
|
||||
// is empty because the printer reports info bits 8-11 = 0xE.
|
||||
tray: [
|
||||
{ id: 0, tray_type: 'PLA', tray_color: 'FF0000' },
|
||||
{ id: 1, tray_type: 'PETG', tray_color: '00FF00' },
|
||||
],
|
||||
},
|
||||
]);
|
||||
(status as any).ams_extruder_map = {};
|
||||
(status as any).fila_switch = {
|
||||
installed: true,
|
||||
in_slots: [-1, 1],
|
||||
out_extruders: [0, 1],
|
||||
stat: 0,
|
||||
info: 2,
|
||||
};
|
||||
|
||||
const result = computeAmsMapping(reqs, status);
|
||||
|
||||
expect(result).toEqual([1]); // Picks AMS 0 tray 1 (PETG green) regardless of nozzle
|
||||
});
|
||||
|
||||
it('still applies nozzle filter when FTS object is null', () => {
|
||||
// Sanity check: explicit null fila_switch behaves like no FTS — nozzle
|
||||
// filter still applies on real dual-nozzle printers.
|
||||
const reqs = {
|
||||
filaments: [
|
||||
{ slot_id: 1, type: 'PLA', color: '#FF0000', used_grams: 10, nozzle_id: 1 },
|
||||
],
|
||||
};
|
||||
const status = createPrinterStatus([
|
||||
{ id: 0, tray: [{ id: 0, tray_type: 'PLA', tray_color: 'FF0000' }] },
|
||||
{ id: 1, tray: [{ id: 0, tray_type: 'PLA', tray_color: 'FF0000' }] },
|
||||
]);
|
||||
(status as any).ams_extruder_map = { '0': 1, '1': 0 };
|
||||
(status as any).fila_switch = null;
|
||||
|
||||
const result = computeAmsMapping(reqs, status);
|
||||
|
||||
expect(result).toEqual([0]); // AMS 0 (left/extruder 1)
|
||||
});
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
|
||||
Reference in New Issue
Block a user