fix(inventory): PA-Profil picker fetches K-profiles across all installed nozzles (#2618)

The Edit Spool "PA-Profil" tab and the SpoolBuddy write-tag page fetched a
printer's calibrations with getKProfiles(printer.id), which defaults the nozzle
filter to 0.4. The printer/MQTT layer filters strictly by that diameter, so on
a multi-nozzle printer a same-filament 0.6mm K-profile was never retrieved and
the picker showed only the 0.4mm entry ("1 match"). (The AMS-Slot config dialog
was already fixed in #1899; these two pickers were not.)

Add installedNozzleDiameters(status) and a shared fetchPrinterCalibrations()
that queries every reported nozzle diameter and merges the results, falling
back to 0.4 when the printer hasn't reported nozzle hardware. Each profile row
now shows a nozzle-diameter badge so identically-named profiles are distinct.
This commit is contained in:
maziggy
2026-07-27 13:08:57 +02:00
parent da33ba64d1
commit 9bb5a1b999
10 changed files with 335 additions and 175 deletions
+4 -16
View File
@@ -8,7 +8,7 @@ import { Button } from './Button';
import { useToast } from '../contexts/ToastContext';
import type { SpoolFormData, PrinterWithCalibrations, ColorPreset } from './spool-form/types';
import { defaultFormData, validateForm, SPOOLMAN_LINKED_FIELDS } from './spool-form/types';
import { buildFilamentOptions, extractBrandsFromPresets, findPresetOption, loadRecentColors, parsePresetName, saveRecentColor } from './spool-form/utils';
import { buildFilamentOptions, extractBrandsFromPresets, fetchPrinterCalibrations, findPresetOption, loadRecentColors, parsePresetName, saveRecentColor } from './spool-form/utils';
import { MATERIALS } from './spool-form/constants';
import { FilamentSection } from './spool-form/FilamentSection';
import { ColorSection } from './spool-form/ColorSection';
@@ -201,21 +201,9 @@ export function SpoolFormModal({
const connected = status?.connected ?? false;
let calibrations: PrinterWithCalibrations['calibrations'] = [];
if (connected) {
try {
const kRes = await api.getKProfiles(printer.id);
calibrations = kRes.profiles.map(p => ({
cali_idx: p.slot_id,
filament_id: p.filament_id,
setting_id: p.setting_id || '',
name: p.name,
k_value: parseFloat(p.k_value) || 0,
n_coef: parseFloat(p.n_coef) || 0,
extruder_id: p.extruder_id,
nozzle_diameter: p.nozzle_diameter,
}));
} catch {
// Printer may not support K-profiles
}
// Fetch across every installed nozzle so dual-nozzle printers
// surface both the 0.4mm and 0.6mm K-profiles, not just 0.4 (#2618).
calibrations = await fetchPrinterCalibrations(printer.id, status);
}
results.push({ printer: { ...printer, connected }, calibrations });
}
@@ -127,6 +127,11 @@ export function PAProfileSection({
</span>
</div>
<div className="flex items-center gap-2 shrink-0">
{cal.nozzle_diameter && (
<span className="text-xs font-mono px-2 py-0.5 rounded bg-bambu-dark text-bambu-gray">
{cal.nozzle_diameter}mm
</span>
)}
<span className="text-xs font-mono px-2 py-0.5 rounded bg-bambu-dark text-bambu-gray">
K={cal.k_value.toFixed(3)}
</span>
+42 -1
View File
@@ -1,7 +1,48 @@
import { api } from '../../api/client';
import type { SlicerSetting, LocalPreset, BuiltinFilament } from '../../api/client';
import type { ColorPreset, FilamentOption } from './types';
import { installedNozzleDiameters } from '../../utils/amsHelpers';
import type { CalibrationProfile, ColorPreset, FilamentOption } from './types';
import { KNOWN_VARIANTS, DEFAULT_BRANDS, RECENT_COLORS_KEY, MAX_RECENT_COLORS } from './constants';
/**
* Fetch a printer's K-profiles across every nozzle it actually has installed
* (#2618) and flatten them into CalibrationProfile rows for the PA-Profil
* picker. `getKProfiles` filters strictly by nozzle diameter and defaults to
* "0.4", so a single call hides non-0.4 profiles (e.g. a 0.6mm PAHT-CF K
* value) — the picker then shows only one of two nozzle-specific profiles.
* We query each installed diameter and merge. Falls back to "0.4" when the
* printer hasn't reported nozzle hardware, preserving prior behaviour.
* Per-diameter failures are swallowed (a printer that doesn't support the
* endpoint just yields no rows), matching the callers' previous try/catch.
*/
export async function fetchPrinterCalibrations(
printerId: number,
status: { nozzles?: { nozzle_diameter?: string }[] } | null | undefined,
): Promise<CalibrationProfile[]> {
const diameters = installedNozzleDiameters(status);
const toFetch = diameters.length > 0 ? diameters : ['0.4'];
const responses = await Promise.all(
toFetch.map(d => api.getKProfiles(printerId, d).catch(() => null)),
);
const calibrations: CalibrationProfile[] = [];
for (const res of responses) {
if (!res) continue;
for (const p of res.profiles) {
calibrations.push({
cali_idx: p.slot_id,
filament_id: p.filament_id,
setting_id: p.setting_id || '',
name: p.name,
k_value: parseFloat(p.k_value) || 0,
n_coef: parseFloat(p.n_coef) || 0,
extruder_id: p.extruder_id,
nozzle_diameter: p.nozzle_diameter,
});
}
}
return calibrations;
}
// Fallback filament presets when cloud is not available
const FALLBACK_PRESETS: FilamentOption[] = [
{ code: 'GFL00', name: 'Bambu PLA Basic', displayName: 'Bambu PLA Basic', isCustom: false, allCodes: ['GFL00'] },