filament_ids.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. """Utility functions for converting between filament_id and setting_id formats, and shared filament constants.
  2. Bambu printers use two ID formats for filament presets:
  3. - **filament_id** (aka tray_info_idx): e.g. "GFL05", "GFG02", "GFA00"
  4. Reported by printer firmware (RFID tags, AMS status).
  5. - **setting_id**: e.g. "GFSL05", "GFSG02", "GFSA00"
  6. Used by BambuStudio / Bambu Cloud API to resolve presets.
  7. The only difference for official Bambu filaments is an "S" inserted after "GF".
  8. User presets (starting with "P") use the same ID in both contexts.
  9. """
  10. MATERIAL_TEMPS: dict[str, tuple[int, int]] = {
  11. "PLA": (190, 230),
  12. "PETG": (220, 260),
  13. "ABS": (240, 270),
  14. "ASA": (240, 270),
  15. "TPU": (200, 240),
  16. "PA": (260, 290),
  17. "PC": (250, 280),
  18. "PVA": (190, 210),
  19. "PLA-CF": (210, 240),
  20. "PETG-CF": (240, 270),
  21. "PA-CF": (270, 300),
  22. }
  23. # Bambu's generic preset per material, for a slot whose spool has no preset of
  24. # its own. Every assignment path and the Configure dialog read this one table;
  25. # a material missing here goes to the printer with an empty tray_info_idx (#3273).
  26. GENERIC_FILAMENT_IDS: dict[str, str] = {
  27. "PLA": "GFL99",
  28. "PETG": "GFG99",
  29. "ABS": "GFB99",
  30. "ASA": "GFB98",
  31. "PC": "GFC99",
  32. "PA": "GFN99",
  33. "NYLON": "GFN99",
  34. "TPU": "GFU99",
  35. "PVA": "GFS99",
  36. "HIPS": "GFS98",
  37. "PLA-CF": "GFL98",
  38. "PETG-CF": "GFG98",
  39. "PA-CF": "GFN98",
  40. "PETG HF": "GFG96",
  41. "PLA SILK": "GFL96",
  42. "PLA HIGH SPEED": "GFL95",
  43. "PCTG": "GFG97",
  44. "PE": "GFP99",
  45. "PP": "GFP97",
  46. }
  47. # The generics the slot-reuse check replaces instead of carrying forward:
  48. # a slot holding one of these gets the generic for the new spool's own
  49. # material. Deliberately the set from before the table above grew (#3273), so
  50. # a slot set to Generic PLA Silk or PLA High Speed still keeps it for a
  51. # preset-less PLA spool, as it always has.
  52. GENERIC_IDS_REPLACED_ON_REUSE: frozenset[str] = frozenset(
  53. {
  54. "GFL99",
  55. "GFL98",
  56. "GFG99",
  57. "GFG98",
  58. "GFG96",
  59. "GFB99",
  60. "GFB98",
  61. "GFC99",
  62. "GFN99",
  63. "GFN98",
  64. "GFU99",
  65. "GFS99",
  66. "GFS98",
  67. }
  68. )
  69. def filament_id_to_setting_id(filament_id: str) -> str:
  70. """Convert filament_id → setting_id (e.g. "GFL05" → "GFSL05").
  71. - Already a setting_id ("GFSL05", "GFSS99") → returned unchanged; a
  72. support filament_id ("GFS99") still converts.
  73. - User presets ("P…") → returned unchanged.
  74. - Empty / unknown → returned unchanged.
  75. """
  76. if not filament_id:
  77. return filament_id
  78. # User presets start with "P" - leave unchanged
  79. if filament_id.startswith("P"):
  80. return filament_id
  81. # Official Bambu presets: GFx## -> GFSx##
  82. if filament_id.startswith("GF") and len(filament_id) >= 4:
  83. # Already a setting_id: "GFS" then the family letter ("GFSL05").
  84. # Support filaments are family S, so their filament_id starts with
  85. # "GFS" too -- but a digit follows it ("GFS99" is Generic PVA, whose
  86. # setting_id is "GFSS99").
  87. if filament_id[2] == "S" and filament_id[3].isalpha():
  88. return filament_id
  89. return f"GFS{filament_id[2:]}"
  90. return filament_id
  91. def setting_id_to_filament_id(setting_id: str) -> str:
  92. """Convert setting_id → filament_id (e.g. "GFSL05" → "GFL05").
  93. - Already a filament_id ("GFL05", or a support one like "GFS99") →
  94. returned unchanged.
  95. - User presets ("P…") → returned unchanged.
  96. - Empty / unknown → returned unchanged.
  97. """
  98. if not setting_id:
  99. return setting_id
  100. # User presets start with "P" - leave unchanged
  101. if setting_id.startswith("P"):
  102. return setting_id
  103. # Setting_id format: GFSx## -> GFx## (remove the "S"). A digit after
  104. # "GFS" means a support filament_id, not a setting_id (see above).
  105. if setting_id.startswith("GFS") and len(setting_id) >= 5 and setting_id[3].isalpha():
  106. return f"GF{setting_id[3:]}"
  107. return setting_id
  108. def normalize_slicer_filament(slicer_filament: str | None) -> tuple[str, str]:
  109. """Normalize a slicer_filament value into (tray_info_idx, setting_id).
  110. The slicer_filament field on a spool can be stored in either format:
  111. - filament_id: "GFL05" (from RFID tag scan)
  112. - setting_id: "GFSL05" or "GFSL05_07" (from cloud preset picker)
  113. Returns (tray_info_idx, setting_id) with version suffixes stripped.
  114. """
  115. raw = slicer_filament or ""
  116. if not raw:
  117. return ("", "")
  118. # Strip version suffix (e.g. "GFSL05_07" → "GFSL05")
  119. base = raw.split("_")[0] if "_" in raw else raw
  120. tray_info_idx = setting_id_to_filament_id(base)
  121. sid = filament_id_to_setting_id(base)
  122. return (tray_info_idx, sid)