33import os
44import traceback
55import uuid
6+ from collections import Counter
67
78from flask import Flask , request , render_template , redirect , url_for
89
3839
3940@app .context_processor
4041def fronted_utilities ():
41- return dict (SPOOLMAN_BASE_URL = SPOOLMAN_BASE_URL , AUTO_SPEND = AUTO_SPEND , color_is_dark = color_is_dark , BASE_URL = BASE_URL , EXTERNAL_SPOOL_AMS_ID = EXTERNAL_SPOOL_AMS_ID , EXTERNAL_SPOOL_ID = EXTERNAL_SPOOL_ID , PRINTER_MODEL = mqtt_bambulab .getPrinterModel (), PRINTER_NAME = PRINTER_NAME )
42+ printer_model = mqtt_bambulab .getPrinterModel () or {}
43+ ams_models_by_id = mqtt_bambulab .getDetectedAmsModelsById ()
44+
45+ return dict (
46+ SPOOLMAN_BASE_URL = SPOOLMAN_BASE_URL ,
47+ AUTO_SPEND = AUTO_SPEND ,
48+ AMS_MODELS_BY_ID = ams_models_by_id ,
49+ color_is_dark = color_is_dark ,
50+ BASE_URL = BASE_URL ,
51+ EXTERNAL_SPOOL_AMS_ID = EXTERNAL_SPOOL_AMS_ID ,
52+ EXTERNAL_SPOOL_ID = EXTERNAL_SPOOL_ID ,
53+ PRINTER_MODEL = printer_model ,
54+ PRINTER_NAME = PRINTER_NAME ,
55+ )
56+
57+
58+ def build_ams_labels (ams_data ):
59+ models_by_id = mqtt_bambulab .getDetectedAmsModelsById ()
60+ base_labels = []
61+ for ams in ams_data :
62+ ams_id = ams .get ("id" )
63+ key = str (ams_id )
64+ base_name = models_by_id .get (key ) or models_by_id .get (ams_id ) or "AMS"
65+ base_labels .append (base_name )
66+
67+ totals = Counter (base_labels )
68+ takt = Counter ()
69+ labels = {}
70+
71+ for ams , base_name in zip (ams_data , base_labels ):
72+ takt [base_name ] += 1
73+ suffix = f" { takt [base_name ]} " if totals [base_name ] > 1 else ""
74+ label = f"{ base_name } { suffix } "
75+ ams_id = ams .get ("id" )
76+ labels [str (ams_id )] = label
77+ labels [ams_id ] = label
78+
79+ return labels
80+
81+
82+ def _augment_tray (spool_list , tray_data , ams_id , tray_id ):
83+ augmentTrayDataWithSpoolMan (spool_list , tray_data , ams_id , tray_id )
84+ if tray_data .get ("unmapped_bambu_tag" ):
85+ spoolman_service .clear_active_spool_for_tray (ams_id , tray_id )
86+ augmentTrayDataWithSpoolMan (spool_list , tray_data , ams_id , tray_id )
4287
4388@app .route ("/issue" )
4489def issue ():
@@ -72,12 +117,12 @@ def issue():
72117
73118 active_spool = None
74119 for spool in spool_list :
75- if spool .get ("extra" ) and spool ["extra" ].get ("active_tray" ) and spool ["extra" ][ "active_tray" ] == json .dumps (trayUid (ams_id , tray_id )):
120+ if spool .get ("extra" ) and spool ["extra" ].get ("active_tray" ) and spool ["extra" ]. get ( "active_tray" ) == json .dumps (trayUid (ams_id , tray_id )):
76121 active_spool = spool
77122 break
78123
79124 if tray_data :
80- augmentTrayDataWithSpoolMan (spool_list , tray_data , trayUid ( ams_id , tray_id ) )
125+ _augment_tray (spool_list , tray_data , ams_id , tray_id )
81126
82127 #TODO: Determine issue
83128 #New bambulab spool
@@ -135,6 +180,73 @@ def fill():
135180
136181 return render_template ('fill.html' , spools = spools , ams_id = ams_id , tray_id = tray_id , materials = materials , selected_materials = selected_materials )
137182
183+ @app .route ("/assign_bambu_spool" )
184+ def assign_bambu_spool ():
185+ if not mqtt_bambulab .isMqttClientConnected ():
186+ return render_template ('error.html' , exception = "MQTT is disconnected. Is the printer online?" )
187+
188+ bambu_tag = request .args .get ("tag" )
189+ ams_id = request .args .get ("ams" )
190+ tray_id = request .args .get ("tray" )
191+ spool_id = request .args .get ("spool_id" )
192+
193+ if not all ([bambu_tag , ams_id , tray_id ]):
194+ return render_template ('error.html' , exception = "Missing AMS ID, Tray ID, or Bambu spool tag." )
195+
196+ if bambu_tag == "00000000000000000000000000000000" :
197+ return render_template ('error.html' , exception = "No Bambu spool was detected in this tray." )
198+
199+ if spool_id :
200+ if READ_ONLY_MODE :
201+ return render_template ('error.html' , exception = "Live read-only mode: linking Bambu spools is disabled." )
202+
203+ spool_data = spoolman_client .getSpoolById (spool_id )
204+ extras = spool_data .get ("extra" ) or {}
205+
206+ spoolman_client .patchExtraTags (spool_id , extras , {
207+ "tag" : json .dumps (bambu_tag ),
208+ })
209+
210+ mqtt_bambulab .setActiveTray (spool_id , extras , ams_id , tray_id )
211+ setActiveSpool (ams_id , tray_id , spool_data )
212+
213+ return redirect (url_for ('home' , success_message = f"Linked Bambu spool to SpoolMan spool { spool_id } on AMS { ams_id } , Tray { tray_id } ." ))
214+
215+ spools = mqtt_bambulab .fetchSpools ()
216+ materials = extract_materials (spools )
217+ selected_materials = []
218+
219+ try :
220+ last_ams_config = mqtt_bambulab .getLastAMSConfig ()
221+ default_material = None
222+
223+ if ams_id == EXTERNAL_SPOOL_AMS_ID :
224+ default_material = last_ams_config .get ("vt_tray" , {}).get ("tray_type" )
225+ else :
226+ for ams in last_ams_config .get ("ams" , []):
227+ if str (ams .get ("id" )) != str (ams_id ):
228+ continue
229+
230+ for tray in ams .get ("tray" , []):
231+ if str (tray .get ("id" )) == str (tray_id ):
232+ default_material = tray .get ("tray_type" )
233+ break
234+
235+ if default_material and default_material in materials :
236+ selected_materials .append (default_material )
237+ except Exception :
238+ pass
239+
240+ return render_template (
241+ 'assign_bambu_spool.html' ,
242+ spools = spools ,
243+ ams_id = ams_id ,
244+ tray_id = tray_id ,
245+ bambu_tag = bambu_tag ,
246+ materials = materials ,
247+ selected_materials = selected_materials ,
248+ )
249+
138250@app .route ("/spool_info" )
139251def spool_info ():
140252 if not mqtt_bambulab .isMqttClientConnected ():
@@ -150,12 +262,12 @@ def spool_info():
150262
151263 issue = False
152264 #TODO: Fix issue when external spool info is reset via bambulab interface
153- augmentTrayDataWithSpoolMan (spool_list , vt_tray_data , trayUid ( EXTERNAL_SPOOL_AMS_ID , EXTERNAL_SPOOL_ID ) )
265+ _augment_tray (spool_list , vt_tray_data , EXTERNAL_SPOOL_AMS_ID , EXTERNAL_SPOOL_ID )
154266 issue |= vt_tray_data .get ("issue" , False )
155267
156268 for ams in ams_data :
157269 for tray in ams ["tray" ]:
158- augmentTrayDataWithSpoolMan (spool_list , tray , trayUid ( ams ["id" ], tray ["id" ]) )
270+ _augment_tray (spool_list , tray , ams ["id" ], tray ["id" ])
159271 issue |= tray .get ("issue" , False )
160272
161273 if not tag_id and not spool_id :
@@ -194,7 +306,8 @@ def spool_info():
194306 break
195307
196308 if current_spool :
197- return render_template ('spool_info.html' , tag_id = tag_id , current_spool = current_spool , ams_data = ams_data , vt_tray_data = vt_tray_data , issue = issue )
309+ ams_labels = build_ams_labels (ams_data )
310+ return render_template ('spool_info.html' , tag_id = tag_id , current_spool = current_spool , ams_data = ams_data , vt_tray_data = vt_tray_data , issue = issue , ams_labels = ams_labels )
198311 else :
199312 return render_template ('error.html' , exception = "Spool not found" )
200313 except Exception as e :
@@ -302,15 +415,16 @@ def home():
302415
303416 issue = False
304417 #TODO: Fix issue when external spool info is reset via bambulab interface
305- augmentTrayDataWithSpoolMan (spool_list , vt_tray_data , trayUid ( EXTERNAL_SPOOL_AMS_ID , EXTERNAL_SPOOL_ID ) )
418+ _augment_tray (spool_list , vt_tray_data , EXTERNAL_SPOOL_AMS_ID , EXTERNAL_SPOOL_ID )
306419 issue |= vt_tray_data ["issue" ]
307420
308421 for ams in ams_data :
309422 for tray in ams ["tray" ]:
310- augmentTrayDataWithSpoolMan (spool_list , tray , trayUid ( ams ["id" ], tray ["id" ]) )
423+ _augment_tray (spool_list , tray , ams ["id" ], tray ["id" ])
311424 issue |= tray ["issue" ]
312425
313- return render_template ('index.html' , success_message = success_message , ams_data = ams_data , vt_tray_data = vt_tray_data , issue = issue )
426+ ams_labels = build_ams_labels (ams_data )
427+ return render_template ('index.html' , success_message = success_message , ams_data = ams_data , vt_tray_data = vt_tray_data , issue = issue , ams_labels = ams_labels )
314428 except Exception as e :
315429 traceback .print_exc ()
316430 return render_template ('error.html' , exception = str (e ))
0 commit comments