mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-09-30 03:01:21 +02:00
Added HMS error handling to printer card
This commit is contained in:
@@ -236,6 +236,10 @@ class BambuMQTTClient:
|
||||
and self._previous_gcode_file is not None
|
||||
)
|
||||
|
||||
if is_new_print or is_file_change:
|
||||
# Clear any old HMS errors when a new print starts
|
||||
self.state.hms_errors = []
|
||||
|
||||
if (is_new_print or is_file_change) and self.on_print_start:
|
||||
logger.info(
|
||||
f"[{self.serial_number}] PRINT START detected - file: {current_file}, "
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
import { X, AlertTriangle, AlertCircle, Info, ExternalLink } from 'lucide-react';
|
||||
import type { HMSError } from '../api/client';
|
||||
|
||||
interface HMSErrorModalProps {
|
||||
printerName: string;
|
||||
errors: HMSError[];
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
// HMS error code descriptions (common ones)
|
||||
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.',
|
||||
};
|
||||
|
||||
function getSeverityInfo(severity: number): { label: string; color: string; bgColor: string; Icon: typeof AlertTriangle } {
|
||||
switch (severity) {
|
||||
case 1:
|
||||
return { label: 'Fatal', color: 'text-red-500', bgColor: 'bg-red-500/20', Icon: AlertTriangle };
|
||||
case 2:
|
||||
return { label: 'Serious', color: 'text-red-400', bgColor: 'bg-red-500/15', Icon: AlertTriangle };
|
||||
case 3:
|
||||
return { label: 'Warning', color: 'text-orange-400', bgColor: 'bg-orange-500/20', Icon: AlertCircle };
|
||||
case 4:
|
||||
default:
|
||||
return { label: 'Info', color: 'text-blue-400', bgColor: 'bg-blue-500/20', Icon: Info };
|
||||
}
|
||||
}
|
||||
|
||||
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}`;
|
||||
}
|
||||
|
||||
export function HMSErrorModal({ printerName, errors, onClose }: HMSErrorModalProps) {
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
|
||||
<div className="bg-bambu-dark-secondary rounded-lg shadow-xl max-w-lg w-full max-h-[80vh] flex flex-col">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between p-4 border-b border-bambu-dark-tertiary">
|
||||
<div className="flex items-center gap-2">
|
||||
<AlertTriangle className="w-5 h-5 text-orange-400" />
|
||||
<h2 className="text-lg font-semibold text-white">HMS Errors - {printerName}</h2>
|
||||
</div>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="p-1 hover:bg-bambu-dark-tertiary rounded-lg transition-colors"
|
||||
>
|
||||
<X className="w-5 h-5 text-bambu-gray" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="flex-1 overflow-y-auto p-4">
|
||||
{errors.length === 0 ? (
|
||||
<div className="text-center py-8 text-bambu-gray">
|
||||
<AlertCircle className="w-12 h-12 mx-auto mb-3 opacity-30" />
|
||||
<p>No HMS errors</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-3">
|
||||
{errors.map((error, index) => {
|
||||
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);
|
||||
|
||||
return (
|
||||
<div
|
||||
key={`${error.code}-${index}`}
|
||||
className={`p-4 rounded-lg ${bgColor} border border-white/10`}
|
||||
>
|
||||
<div className="flex items-start gap-3">
|
||||
<Icon className={`w-5 h-5 ${color} flex-shrink-0 mt-0.5`} />
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<span className={`font-mono text-sm ${color}`}>{error.code}</span>
|
||||
<span className={`text-xs px-2 py-0.5 rounded-full ${bgColor} ${color}`}>
|
||||
{label}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-sm text-bambu-gray mb-2">{description}</p>
|
||||
<a
|
||||
href={wikiUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="inline-flex items-center gap-1 text-xs text-bambu-green hover:underline"
|
||||
>
|
||||
<ExternalLink className="w-3 h-3" />
|
||||
View on Bambu Lab Wiki
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div className="p-4 border-t border-bambu-dark-tertiary">
|
||||
<p className="text-xs text-bambu-gray">
|
||||
HMS (Health Management System) monitors printer health. Clear errors on the printer to dismiss them here.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import { Button } from '../components/Button';
|
||||
import { ConfirmModal } from '../components/ConfirmModal';
|
||||
import { FileManagerModal } from '../components/FileManagerModal';
|
||||
import { MQTTDebugModal } from '../components/MQTTDebugModal';
|
||||
import { HMSErrorModal } from '../components/HMSErrorModal';
|
||||
|
||||
function formatTime(seconds: number): string {
|
||||
const hours = Math.floor(seconds / 3600);
|
||||
@@ -88,6 +89,7 @@ function PrinterCard({ printer, hideIfDisconnected }: { printer: Printer; hideIf
|
||||
const [showMQTTDebug, setShowMQTTDebug] = useState(false);
|
||||
const [showPowerOnConfirm, setShowPowerOnConfirm] = useState(false);
|
||||
const [showPowerOffConfirm, setShowPowerOffConfirm] = useState(false);
|
||||
const [showHMSModal, setShowHMSModal] = useState(false);
|
||||
|
||||
const { data: status } = useQuery({
|
||||
queryKey: ['printerStatus', printer.id],
|
||||
@@ -173,25 +175,22 @@ function PrinterCard({ printer, hideIfDisconnected }: { printer: Printer; hideIf
|
||||
</span>
|
||||
{/* HMS Status Indicator */}
|
||||
{status?.connected && (
|
||||
<span
|
||||
className={`flex items-center gap-1 px-2 py-1 rounded-full text-xs ${
|
||||
<button
|
||||
onClick={() => setShowHMSModal(true)}
|
||||
className={`flex items-center gap-1 px-2 py-1 rounded-full text-xs cursor-pointer hover:opacity-80 transition-opacity ${
|
||||
status.hms_errors && status.hms_errors.length > 0
|
||||
? status.hms_errors.some(e => e.severity <= 2)
|
||||
? 'bg-red-500/20 text-red-400'
|
||||
: 'bg-orange-500/20 text-orange-400'
|
||||
: 'bg-bambu-green/20 text-bambu-green'
|
||||
}`}
|
||||
title={
|
||||
status.hms_errors && status.hms_errors.length > 0
|
||||
? `${status.hms_errors.length} HMS error(s)`
|
||||
: 'No HMS errors'
|
||||
}
|
||||
title="Click to view HMS errors"
|
||||
>
|
||||
<AlertTriangle className="w-3 h-3" />
|
||||
{status.hms_errors && status.hms_errors.length > 0
|
||||
? status.hms_errors.length
|
||||
: 'OK'}
|
||||
</span>
|
||||
</button>
|
||||
)}
|
||||
<div className="relative">
|
||||
<Button
|
||||
@@ -491,6 +490,15 @@ function PrinterCard({ printer, hideIfDisconnected }: { printer: Printer; hideIf
|
||||
onCancel={() => setShowPowerOffConfirm(false)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* HMS Error Modal */}
|
||||
{showHMSModal && (
|
||||
<HMSErrorModal
|
||||
printerName={printer.name}
|
||||
errors={status?.hms_errors || []}
|
||||
onClose={() => setShowHMSModal(false)}
|
||||
/>
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2
-2
@@ -7,8 +7,8 @@
|
||||
<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-B0NJFRfx.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BKPvAiVm.css">
|
||||
<script type="module" crossorigin src="/assets/index-8ml33qQA.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BKGWUT04.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
Reference in New Issue
Block a user