فهرست منبع

Auto-control chamber light for plate detection
- Automatically turn on chamber light before plate check if it's off
- Restore light to original state after modal closes or check completes
- Add 2.5s delay for light to turn on and camera to adjust exposure
- Remove manual light warning from plate check modal
- Apply to both manual plate checks (modal) and automatic checks on print start

maziggy 4 ماه پیش
والد
کامیت
cc4dd3a0e8

+ 16 - 0
backend/app/main.py

@@ -734,6 +734,17 @@ async def on_print_start(printer_id: int, data: dict):
                         printer.plate_detection_roi_h,
                     )
 
+                # Auto-turn on chamber light if it's off for better detection
+                light_was_off = False
+                client = printer_manager.get_client(printer_id)
+                if client and client.state:
+                    light_was_off = not client.state.chamber_light
+                    if light_was_off:
+                        logger.info(f"[PLATE CHECK] Turning on chamber light for printer {printer_id}")
+                        client.set_chamber_light(True)
+                        # Wait for light to physically turn on and camera to adjust exposure
+                        await asyncio.sleep(2.5)
+
                 logger.info(f"[PLATE CHECK] Running plate detection for printer {printer_id}")
                 plate_result = await check_plate_empty(
                     printer_id=printer_id,
@@ -747,6 +758,11 @@ async def on_print_start(printer_id: int, data: dict):
                     roi=roi,
                 )
 
+                # Restore chamber light to original state
+                if light_was_off and client:
+                    logger.info(f"[PLATE CHECK] Restoring chamber light to off for printer {printer_id}")
+                    client.set_chamber_light(False)
+
                 if not plate_result.needs_calibration and not plate_result.is_empty:
                     # Objects detected - pause the print!
                     logger.warning(

+ 35 - 21
frontend/src/pages/PrintersPage.tsx

@@ -1,4 +1,4 @@
-import { useState, useEffect, useMemo, useRef } from 'react';
+import { useState, useEffect, useMemo, useRef, useCallback } from 'react';
 import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
 import { useTheme } from '../contexts/ThemeContext';
 import {
@@ -984,6 +984,7 @@ function PrinterCard({
   const [isCalibrating, setIsCalibrating] = useState(false);
   const [editingRoi, setEditingRoi] = useState<{ x: number; y: number; w: number; h: number } | null>(null);
   const [isSavingRoi, setIsSavingRoi] = useState(false);
+  const [plateCheckLightWasOff, setPlateCheckLightWasOff] = useState(false);
 
   const { data: status } = useQuery({
     queryKey: ['printerStatus', printer.id],
@@ -1305,17 +1306,43 @@ function PrinterCard({
   const handleOpenPlateManagement = async () => {
     setIsCheckingPlate(true);
     setPlateCheckResult(null);
+
+    // Auto-turn on light if it's off
+    const lightWasOff = status?.chamber_light === false;
+    setPlateCheckLightWasOff(lightWasOff);
+    if (lightWasOff) {
+      await api.setChamberLight(printer.id, true);
+      // Wait for light to physically turn on and camera to adjust exposure
+      // (MQTT command is async, light takes ~1s to turn on, camera needs time to adjust)
+      await new Promise(resolve => setTimeout(resolve, 2500));
+    }
+
     try {
       const result = await api.checkPlateEmpty(printer.id, { includeDebugImage: true });
       setPlateCheckResult(result);
       fetchPlateReferences();
     } catch (error) {
       showToast(error instanceof Error ? error.message : 'Failed to check plate', 'error');
+      // Restore light if check failed
+      if (lightWasOff) {
+        await api.setChamberLight(printer.id, false);
+        setPlateCheckLightWasOff(false);
+      }
     } finally {
       setIsCheckingPlate(false);
     }
   };
 
+  // Close plate check modal and restore light state
+  const closePlateCheckModal = useCallback(async () => {
+    setPlateCheckResult(null);
+    // Restore light to original state if we turned it on
+    if (plateCheckLightWasOff) {
+      await api.setChamberLight(printer.id, false);
+      setPlateCheckLightWasOff(false);
+    }
+  }, [plateCheckLightWasOff, printer.id]);
+
   // Calibrate plate detection handler
   const handleCalibratePlate = async (label?: string) => {
     setIsCalibrating(true);
@@ -1384,12 +1411,12 @@ function PrinterCard({
   useEffect(() => {
     const handleEscape = (e: KeyboardEvent) => {
       if (e.key === 'Escape' && plateCheckResult) {
-        setPlateCheckResult(null);
+        closePlateCheckModal();
       }
     };
     window.addEventListener('keydown', handleEscape);
     return () => window.removeEventListener('keydown', handleEscape);
-  }, [plateCheckResult]);
+  }, [plateCheckResult, closePlateCheckModal]);
 
   // Watch ams_status_main to detect when RFID read completes
   // ams_status_main: 0=idle, 2=rfid_identifying
@@ -2766,7 +2793,7 @@ function PrinterCard({
 
       {/* Plate Check Result Modal */}
       {plateCheckResult && (
-        <div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4" onClick={() => setPlateCheckResult(null)}>
+        <div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4" onClick={() => closePlateCheckModal()}>
           <div className="bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-xl shadow-2xl max-w-lg w-full" onClick={e => e.stopPropagation()}>
             <div className="flex items-center justify-between p-4 border-b border-bambu-dark-tertiary">
               <div className="flex items-center gap-2">
@@ -2787,26 +2814,13 @@ function PrinterCard({
                 )}
               </div>
               <button
-                onClick={() => setPlateCheckResult(null)}
+                onClick={() => closePlateCheckModal()}
                 className="p-1 text-bambu-gray hover:text-white rounded transition-colors"
               >
                 <X className="w-5 h-5" />
               </button>
             </div>
             <div className="p-4 space-y-4">
-              {/* Light Warning */}
-              {plateCheckResult.light_warning && (
-                <div className="p-3 rounded-lg bg-yellow-500/20 border border-yellow-500/50">
-                  <p className="font-medium text-yellow-400 flex items-center gap-2">
-                    <AlertTriangle className="w-4 h-4" />
-                    Chamber light is OFF
-                  </p>
-                  <p className="text-sm text-bambu-gray mt-1">
-                    For reliable detection, please turn ON the chamber light before checking or calibrating.
-                  </p>
-                </div>
-              )}
-
               {plateCheckResult.needs_calibration ? (
                 <>
                   <div className="p-3 rounded-lg bg-blue-500/20 border border-blue-500/50">
@@ -2814,7 +2828,7 @@ function PrinterCard({
                       Calibration Required
                     </p>
                     <p className="text-sm text-bambu-gray mt-1">
-                      Please ensure the build plate is <strong>completely empty</strong> and chamber light is <strong>ON</strong>, then click Calibrate.
+                      Please ensure the build plate is <strong>completely empty</strong>, then click Calibrate.
                     </p>
                   </div>
                   <div className="text-sm text-bambu-gray space-y-2">
@@ -3013,7 +3027,7 @@ function PrinterCard({
             <div className="flex justify-end gap-2 p-4 border-t border-bambu-dark-tertiary">
               {plateCheckResult.needs_calibration ? (
                 <>
-                  <Button variant="ghost" onClick={() => setPlateCheckResult(null)}>
+                  <Button variant="ghost" onClick={() => closePlateCheckModal()}>
                     Cancel
                   </Button>
                   <Button
@@ -3035,7 +3049,7 @@ function PrinterCard({
                   <Button variant="ghost" onClick={() => handleCalibratePlate()} disabled={isCalibrating}>
                     {isCalibrating ? 'Adding...' : `Add Reference (${plateReferences?.references.length || 0}/${plateReferences?.max_references || 5})`}
                   </Button>
-                  <Button onClick={() => setPlateCheckResult(null)}>
+                  <Button onClick={() => closePlateCheckModal()}>
                     Close
                   </Button>
                 </>

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
static/assets/index-C4B4iLcH.css


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
static/assets/index-CwW-gspw.css


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
static/assets/index-nyN_9kgu.js


+ 2 - 2
static/index.html

@@ -23,8 +23,8 @@
 
     <!-- Splash screens for iOS -->
     <link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
-    <script type="module" crossorigin src="/assets/index-BpwPeQpb.js"></script>
-    <link rel="stylesheet" crossorigin href="/assets/index-C4B4iLcH.css">
+    <script type="module" crossorigin src="/assets/index-nyN_9kgu.js"></script>
+    <link rel="stylesheet" crossorigin href="/assets/index-CwW-gspw.css">
   </head>
   <body>
     <div id="root"></div>

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است