Browse Source

Fixed bug when retrieving k profiles from printer

Martin Ziegler 5 months ago
parent
commit
faeae88aef

+ 5 - 0
README.md

@@ -134,6 +134,11 @@ v∆v
   <br><em>Cloud Profiles</em>
 </p>
 
+<p align="center">
+  <img src="docs/screenshots/maintenance.png" alt="Maintenance" width="800">
+  <br><em>Maintenance</em>
+</p>
+
 <p align="center">
   <img src="docs/screenshots/settings.png" alt="Settings" width="800">
   <br><em>Settings</em>

+ 24 - 4
backend/app/services/bambu_mqtt.py

@@ -178,6 +178,8 @@ class BambuMQTTClient:
                 )
 
             # Check for K-profile response (extrusion_cali)
+            if "command" in print_data:
+                logger.debug(f"[{self.serial_number}] Received command response: {print_data.get('command')}")
             if "command" in print_data and print_data.get("command") == "extrusion_cali_get":
                 self._handle_kprofile_response(print_data)
 
@@ -410,8 +412,14 @@ class BambuMQTTClient:
             message = {"pushing": {"command": "pushall"}}
             self._client.publish(self.topic_publish, json.dumps(message))
 
-    def connect(self):
-        """Connect to the printer MQTT broker."""
+    def connect(self, loop: asyncio.AbstractEventLoop | None = None):
+        """Connect to the printer MQTT broker.
+
+        Args:
+            loop: The asyncio event loop to use for thread-safe callbacks.
+                  If not provided, will try to get the running loop.
+        """
+        self._loop = loop
         self._client = mqtt.Client(
             callback_api_version=mqtt.CallbackAPIVersion.VERSION2,
             client_id=f"bambutrack_{self.serial_number}",
@@ -550,12 +558,17 @@ class BambuMQTTClient:
         self._kprofile_response_data = profiles
 
         # Signal that we received the response
+        # Use thread-safe method since MQTT callbacks run in a different thread
         if self._pending_kprofile_response:
-            self._pending_kprofile_response.set()
+            if self._loop and self._loop.is_running():
+                self._loop.call_soon_threadsafe(self._pending_kprofile_response.set)
+            else:
+                # Fallback for when loop is not available
+                self._pending_kprofile_response.set()
 
         logger.info(f"[{self.serial_number}] Received {len(profiles)} K-profiles")
 
-    async def get_kprofiles(self, nozzle_diameter: str = "0.4", timeout: float = 5.0) -> list[KProfile]:
+    async def get_kprofiles(self, nozzle_diameter: str = "0.4", timeout: float = 10.0) -> list[KProfile]:
         """Request K-profiles from the printer.
 
         Args:
@@ -569,6 +582,13 @@ class BambuMQTTClient:
             logger.warning(f"[{self.serial_number}] Cannot get K-profiles: not connected")
             return []
 
+        # Capture current event loop for thread-safe callback
+        try:
+            self._loop = asyncio.get_running_loop()
+        except RuntimeError:
+            logger.warning(f"[{self.serial_number}] No running event loop")
+            return []
+
         # Set up response event
         self._sequence_id += 1
         self._pending_kprofile_response = asyncio.Event()

BIN
docs/screenshots/maintenance.png


+ 27 - 7
frontend/src/components/KProfilesView.tsx

@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import React, { useState, useEffect } from 'react';
 import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
 import {
   Gauge,
@@ -499,11 +499,37 @@ export function KProfilesView() {
     queryFn: () => api.getKProfiles(selectedPrinter!, nozzleDiameter),
     enabled: !!selectedPrinter,
     retry: false,
+    staleTime: 0,  // Always consider data stale to ensure fresh fetch
+    refetchOnMount: 'always',  // Always refetch when component mounts
   });
 
   // Check if error is due to printer not being connected
   const isOfflineError = kprofilesError?.message?.includes('not connected');
 
+  // Auto-select first connected printer
+  useEffect(() => {
+    if (!selectedPrinter && printers && printers.length > 0) {
+      const activePrinter = printers.find((p) => p.is_active);
+      if (activePrinter) {
+        setSelectedPrinter(activePrinter.id);
+      }
+    }
+  }, [selectedPrinter, printers]);
+
+  // Refetch profiles when printer selection changes
+  useEffect(() => {
+    if (selectedPrinter) {
+      // Delay refetch to ensure query is enabled after state update
+      const timer = setTimeout(() => {
+        refetchProfiles();
+      }, 150);
+      return () => clearTimeout(timer);
+    }
+  }, [selectedPrinter, nozzleDiameter]); // eslint-disable-line react-hooks/exhaustive-deps
+
+  // Get connected printers for display
+  const connectedPrinters = printers?.filter((p) => p.is_active) || [];
+
   // Filter profiles based on search query, extruder filter, and flow type
   const filteredProfiles = React.useMemo(() => {
     if (!kprofiles?.profiles) return [];
@@ -532,12 +558,6 @@ export function KProfilesView() {
     });
   }, [kprofiles?.profiles, searchQuery, extruderFilter, flowTypeFilter]);
 
-  // Auto-select first connected printer
-  const connectedPrinters = printers?.filter((p) => p.is_active) || [];
-  if (!selectedPrinter && connectedPrinters.length > 0) {
-    setSelectedPrinter(connectedPrinters[0].id);
-  }
-
   // Check if selected printer is dual-nozzle (auto-detected from MQTT temperature data)
   const selectedPrinterData = printers?.find((p) => p.id === selectedPrinter);
   const isDualNozzle = selectedPrinterData?.nozzle_count === 2;

File diff suppressed because it is too large
+ 0 - 0
static/assets/index-CKBzHHT0.js


+ 1 - 1
static/index.html

@@ -7,7 +7,7 @@
     <link rel="icon" type="image/png" sizes="32x32" href="/img/favicon-32x32.png" />
     <link rel="icon" type="image/png" sizes="16x16" href="/img/favicon-16x16.png" />
     <link rel="apple-touch-icon" sizes="180x180" href="/img/apple-touch-icon.png" />
-    <script type="module" crossorigin src="/assets/index-DqWJuns8.js"></script>
+    <script type="module" crossorigin src="/assets/index-CKBzHHT0.js"></script>
     <link rel="stylesheet" crossorigin href="/assets/index-H_ymON9v.css">
   </head>
   <body>

Some files were not shown because too many files changed in this diff