Browse Source

Fixed bug in HMS module

Martin Ziegler 5 months ago
parent
commit
dd02acd97a

+ 1 - 1
backend/app/api/routes/printers.py

@@ -146,7 +146,7 @@ async def get_printer_status(printer_id: int, db: AsyncSession = Depends(get_db)
 
 
     # Convert HMS errors to response format
     # Convert HMS errors to response format
     hms_errors = [
     hms_errors = [
-        HMSErrorResponse(code=e.code, module=e.module, severity=e.severity)
+        HMSErrorResponse(code=e.code, attr=e.attr, module=e.module, severity=e.severity)
         for e in (state.hms_errors or [])
         for e in (state.hms_errors or [])
     ]
     ]
 
 

+ 1 - 0
backend/app/schemas/printer.py

@@ -39,6 +39,7 @@ class PrinterResponse(PrinterBase):
 
 
 class HMSErrorResponse(BaseModel):
 class HMSErrorResponse(BaseModel):
     code: str
     code: str
+    attr: int = 0  # Attribute value for constructing wiki URL
     module: int
     module: int
     severity: int  # 1=fatal, 2=serious, 3=common, 4=info
     severity: int  # 1=fatal, 2=serious, 3=common, 4=info
 
 

+ 17 - 15
backend/app/services/bambu_mqtt.py

@@ -26,6 +26,7 @@ class MQTTLogEntry:
 class HMSError:
 class HMSError:
     """Health Management System error from printer."""
     """Health Management System error from printer."""
     code: str
     code: str
+    attr: int  # Attribute value for constructing wiki URL
     module: int
     module: int
     severity: int  # 1=fatal, 2=serious, 3=common, 4=info
     severity: int  # 1=fatal, 2=serious, 3=common, 4=info
     message: str = ""
     message: str = ""
@@ -967,23 +968,24 @@ class BambuMQTTClient:
             if isinstance(hms_list, list):
             if isinstance(hms_list, list):
                 for hms in hms_list:
                 for hms in hms_list:
                     if isinstance(hms, dict):
                     if isinstance(hms, dict):
-                        # HMS format: {"attr": code, "code": full_code}
-                        # The code is a hex string, severity is in bits
-                        code = hms.get("code", hms.get("attr", "0"))
-                        if isinstance(code, int):
-                            code = hex(code)
-                        # Parse severity from code (typically last 4 bits indicate level)
-                        try:
-                            code_int = int(str(code).replace("0x", ""), 16) if code else 0
-                            severity = (code_int >> 16) & 0xF  # Extract severity bits
-                            module = (code_int >> 24) & 0xFF  # Extract module bits
-                        except (ValueError, TypeError):
-                            severity = 3
-                            module = 0
+                        # HMS format: {"attr": attribute_code, "code": error_code}
+                        # attr contains module/severity info, code contains error number
+                        # Both are needed to construct the wiki URL
+                        attr = hms.get("attr", 0)
+                        code = hms.get("code", 0)
+                        if isinstance(attr, str):
+                            attr = int(attr.replace("0x", ""), 16) if attr else 0
+                        if isinstance(code, str):
+                            code = int(code.replace("0x", ""), 16) if code else 0
+                        # Severity is in attr byte 1 (bits 8-15)
+                        severity = (attr >> 8) & 0xF
+                        # Module is in attr byte 3 (bits 24-31)
+                        module = (attr >> 24) & 0xFF
                         self.state.hms_errors.append(HMSError(
                         self.state.hms_errors.append(HMSError(
-                            code=str(code),
+                            code=f"0x{code:x}" if code else "0x0",
+                            attr=attr,
                             module=module,
                             module=module,
-                            severity=severity if severity > 0 else 3,
+                            severity=severity if severity > 0 else 2,
                         ))
                         ))
 
 
         # Parse SD card status
         # Parse SD card status

+ 1 - 1
backend/app/services/printer_manager.py

@@ -280,7 +280,7 @@ def printer_state_to_dict(state: PrinterState, printer_id: int | None = None) ->
         "total_layers": state.total_layers,
         "total_layers": state.total_layers,
         "temperatures": state.temperatures,
         "temperatures": state.temperatures,
         "hms_errors": [
         "hms_errors": [
-            {"code": e.code, "module": e.module, "severity": e.severity}
+            {"code": e.code, "attr": e.attr, "module": e.module, "severity": e.severity}
             for e in (state.hms_errors or [])
             for e in (state.hms_errors or [])
         ],
         ],
     }
     }

+ 1 - 0
frontend/src/api/client.ts

@@ -37,6 +37,7 @@ export interface Printer {
 
 
 export interface HMSError {
 export interface HMSError {
   code: string;
   code: string;
+  attr: number;  // Attribute value for constructing wiki URL
   module: number;
   module: number;
   severity: number;  // 1=fatal, 2=serious, 3=common, 4=info
   severity: number;  // 1=fatal, 2=serious, 3=common, 4=info
 }
 }

+ 54 - 25
frontend/src/components/HMSErrorModal.tsx

@@ -1,3 +1,4 @@
+// HMS Error Modal - Updated Dec 4 2025 for attr field support
 import { useEffect } from 'react';
 import { useEffect } from 'react';
 import { X, AlertTriangle, AlertCircle, Info, ExternalLink } from 'lucide-react';
 import { X, AlertTriangle, AlertCircle, Info, ExternalLink } from 'lucide-react';
 import type { HMSError } from '../api/client';
 import type { HMSError } from '../api/client';
@@ -8,20 +9,25 @@ interface HMSErrorModalProps {
   onClose: () => void;
   onClose: () => void;
 }
 }
 
 
-// HMS error code descriptions (common ones)
+// HMS error code descriptions keyed by full HMS code (attr + code combined)
+// Format: "AAAA_BBBB_CCCC_DDDD" where AAAA_BBBB is from attr, CCCC_DDDD is from code
 const HMS_DESCRIPTIONS: Record<string, string> = {
 const HMS_DESCRIPTIONS: Record<string, string> = {
-  '0x20054': 'The heatbed temperature is abnormal. The sensor may be disconnected or damaged.',
-  '0x50005': 'Motor driver overheated. Let the printer cool down.',
-  '0x50006': 'Motor driver communication error.',
-  '0x70001': 'AMS communication error.',
-  '0x70002': 'AMS filament runout.',
-  '0x70003': 'AMS filament not detected.',
-  '0xC0003': 'First layer inspection failed.',
-  '0xC0004': 'Nozzle clog detected.',
-  '0xC8000': 'Foreign object detected on print bed.',
-  '0x50000': 'Motor X axis lost steps.',
-  '0x50001': 'Motor Y axis lost steps.',
-  '0x50002': 'Motor Z axis lost steps.',
+  // H2D specific errors
+  '0700_5500_0002_0001': 'A binding error occurred between AMS and the extruder. Please perform AMS initialization again.',
+  '0500_0300_0002_000E': 'Some modules are incompatible with the printer firmware version. Please update firmware.',
+  // Common errors
+  '0300_0100_0002_0054': 'The heatbed temperature is abnormal. The sensor may be disconnected or damaged.',
+  '0500_0100_0005_0005': 'Motor driver overheated. Let the printer cool down.',
+  '0500_0100_0005_0006': 'Motor driver communication error.',
+  '0700_0100_0007_0001': 'AMS communication error.',
+  '0700_0100_0007_0002': 'AMS filament runout.',
+  '0700_0100_0007_0003': 'AMS filament not detected.',
+  '0C00_0100_000C_0003': 'First layer inspection failed.',
+  '0C00_0100_000C_0004': 'Nozzle clog detected.',
+  '0C00_0100_000C_8000': 'Foreign object detected on print bed.',
+  '0500_0100_0005_0000': 'Motor X axis lost steps.',
+  '0500_0100_0005_0001': 'Motor Y axis lost steps.',
+  '0500_0100_0005_0002': 'Motor Z axis lost steps.',
 };
 };
 
 
 function getSeverityInfo(severity: number): { label: string; color: string; bgColor: string; Icon: typeof AlertTriangle } {
 function getSeverityInfo(severity: number): { label: string; color: string; bgColor: string; Icon: typeof AlertTriangle } {
@@ -38,18 +44,38 @@ function getSeverityInfo(severity: number): { label: string; color: string; bgCo
   }
   }
 }
 }
 
 
-function getHMSWikiUrl(code: string): string {
-  // Convert hex code to format used by Bambu Lab wiki
-  // Example: 0x20054 -> HMS_0200_0005_0004
-  const codeNum = parseInt(code.replace('0x', ''), 16);
-  const part1 = ((codeNum >> 24) & 0xFF).toString(16).padStart(2, '0').toUpperCase();
-  const part2 = ((codeNum >> 16) & 0xFF).toString(16).padStart(2, '0').toUpperCase();
-  const part3 = ((codeNum >> 8) & 0xFF).toString(16).padStart(2, '0').toUpperCase();
-  const part4 = (codeNum & 0xFF).toString(16).padStart(2, '0').toUpperCase();
-  return `https://wiki.bambulab.com/en/x1/troubleshooting/hmscode/HMS_${part1}${part2}_${part3}${part4}`;
+function getFullHMSCode(attr: number, code: number): string {
+  // Construct the full HMS code from attr and code
+  // Format: AAAA_BBBB_CCCC_DDDD
+  // AAAA_BBBB from attr, CCCC_DDDD from code
+  const a1 = ((attr >> 24) & 0xFF).toString(16).padStart(2, '0').toUpperCase();
+  const a2 = ((attr >> 16) & 0xFF).toString(16).padStart(2, '0').toUpperCase();
+  const a3 = ((attr >> 8) & 0xFF).toString(16).padStart(2, '0').toUpperCase();
+  const a4 = (attr & 0xFF).toString(16).padStart(2, '0').toUpperCase();
+
+  const c1 = ((code >> 24) & 0xFF).toString(16).padStart(2, '0').toUpperCase();
+  const c2 = ((code >> 16) & 0xFF).toString(16).padStart(2, '0').toUpperCase();
+  const c3 = ((code >> 8) & 0xFF).toString(16).padStart(2, '0').toUpperCase();
+  const c4 = (code & 0xFF).toString(16).padStart(2, '0').toUpperCase();
+
+  return `${a1}${a2}_${a3}${a4}_${c1}${c2}_${c3}${c4}`;
+}
+
+function getHMSWikiUrl(attr: number, code: number, printerName: string): string {
+  // Construct wiki URL from attr and code
+  const fullCode = getFullHMSCode(attr, code);
+
+  // Use H2 wiki path for H2D printers, otherwise use X1 path
+  const isH2 = printerName.toLowerCase().includes('h2');
+  const basePath = isH2 ? 'h2' : 'x1';
+
+  return `https://wiki.bambulab.com/en/${basePath}/troubleshooting/hmscode/${fullCode}`;
 }
 }
 
 
 export function HMSErrorModal({ printerName, errors, onClose }: HMSErrorModalProps) {
 export function HMSErrorModal({ printerName, errors, onClose }: HMSErrorModalProps) {
+  // Debug: log errors to see what data we're receiving
+  console.log('HMSErrorModal errors:', JSON.stringify(errors, null, 2));
+
   // Close on Escape key
   // Close on Escape key
   useEffect(() => {
   useEffect(() => {
     const handleKeyDown = (e: KeyboardEvent) => {
     const handleKeyDown = (e: KeyboardEvent) => {
@@ -87,8 +113,11 @@ export function HMSErrorModal({ printerName, errors, onClose }: HMSErrorModalPro
             <div className="space-y-3">
             <div className="space-y-3">
               {errors.map((error, index) => {
               {errors.map((error, index) => {
                 const { label, color, bgColor, Icon } = getSeverityInfo(error.severity);
                 const { label, color, bgColor, Icon } = getSeverityInfo(error.severity);
-                const description = HMS_DESCRIPTIONS[error.code] || 'Unknown error. Click the link below for details.';
-                const wikiUrl = getHMSWikiUrl(error.code);
+                const codeNum = parseInt(error.code.replace('0x', ''), 16) || 0;
+                const fullHMSCode = getFullHMSCode(error.attr, codeNum);
+                const description = HMS_DESCRIPTIONS[fullHMSCode] || 'Unknown error. Click the link below for details.';
+                const wikiUrl = getHMSWikiUrl(error.attr, codeNum, printerName);
+                const displayCode = `HMS_${fullHMSCode.replace(/_/g, '-')}`;
 
 
                 return (
                 return (
                   <div
                   <div
@@ -99,7 +128,7 @@ export function HMSErrorModal({ printerName, errors, onClose }: HMSErrorModalPro
                       <Icon className={`w-5 h-5 ${color} flex-shrink-0 mt-0.5`} />
                       <Icon className={`w-5 h-5 ${color} flex-shrink-0 mt-0.5`} />
                       <div className="flex-1 min-w-0">
                       <div className="flex-1 min-w-0">
                         <div className="flex items-center gap-2 mb-1">
                         <div className="flex items-center gap-2 mb-1">
-                          <span className={`font-mono text-sm ${color}`}>{error.code}</span>
+                          <span className={`font-mono text-sm ${color}`}>{displayCode}</span>
                           <span className={`text-xs px-2 py-0.5 rounded-full ${bgColor} ${color}`}>
                           <span className={`text-xs px-2 py-0.5 rounded-full ${bgColor} ${color}`}>
                             {label}
                             {label}
                           </span>
                           </span>

File diff suppressed because it is too large
+ 0 - 0
static/assets/index-06aT7AZk.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="32x32" href="/img/favicon-32x32.png" />
     <link rel="icon" type="image/png" sizes="16x16" href="/img/favicon-16x16.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" />
     <link rel="apple-touch-icon" sizes="180x180" href="/img/apple-touch-icon.png" />
-    <script type="module" crossorigin src="/assets/index-KY24LvJj.js"></script>
+    <script type="module" crossorigin src="/assets/index-06aT7AZk.js"></script>
     <link rel="stylesheet" crossorigin href="/assets/index-BAV1KG6Z.css">
     <link rel="stylesheet" crossorigin href="/assets/index-BAV1KG6Z.css">
   </head>
   </head>
   <body>
   <body>

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