mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-08 07:01:40 +02:00
Add toggle to disable printer firmware update checks
Add new setting "Check printer firmware" in Settings → General → Updates that allows users to disable automatic firmware update checks from Bambu Lab servers. Closes #169
This commit is contained in:
@@ -5,6 +5,9 @@ All notable changes to Bambuddy will be documented in this file.
|
||||
## [0.1.6-final] - Not released
|
||||
|
||||
### New Features
|
||||
- **Disable Printer Firmware Checks** - New toggle in Settings → General → Updates to disable printer firmware update checks:
|
||||
- Prevents Bambuddy from checking Bambu Lab servers for firmware updates
|
||||
- Useful for users who prefer to manage firmware manually or have network restrictions
|
||||
- **Archive Plate Browsing** - Browse plate thumbnails directly in archive cards (Issue #166):
|
||||
- Hover over archive card to reveal plate navigation for multi-plate files
|
||||
- Left/right arrows to cycle through plate thumbnails
|
||||
|
||||
@@ -74,6 +74,7 @@ async def get_settings(db: AsyncSession = Depends(get_db)):
|
||||
"capture_finish_photo",
|
||||
"spoolman_enabled",
|
||||
"check_updates",
|
||||
"check_printer_firmware",
|
||||
"virtual_printer_enabled",
|
||||
"ftp_retry_enabled",
|
||||
"mqtt_enabled",
|
||||
|
||||
@@ -26,6 +26,7 @@ class AppSettings(BaseModel):
|
||||
|
||||
# Updates
|
||||
check_updates: bool = Field(default=True, description="Automatically check for updates on startup")
|
||||
check_printer_firmware: bool = Field(default=True, description="Check for printer firmware updates from Bambu Lab")
|
||||
|
||||
# Language
|
||||
notification_language: str = Field(default="en", description="Language for push notifications (en, de)")
|
||||
@@ -134,6 +135,7 @@ class AppSettingsUpdate(BaseModel):
|
||||
spoolman_url: str | None = None
|
||||
spoolman_sync_mode: str | None = None
|
||||
check_updates: bool | None = None
|
||||
check_printer_firmware: bool | None = None
|
||||
notification_language: str | None = None
|
||||
ams_humidity_good: int | None = None
|
||||
ams_humidity_fair: int | None = None
|
||||
|
||||
@@ -215,6 +215,28 @@ class TestSettingsAPI:
|
||||
assert result["currency"] == "JPY"
|
||||
assert result["check_updates"] is False
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.integration
|
||||
async def test_update_check_printer_firmware(self, async_client: AsyncClient):
|
||||
"""Verify check_printer_firmware can be updated."""
|
||||
# Default should be True
|
||||
response = await async_client.get("/api/v1/settings/")
|
||||
assert response.json()["check_printer_firmware"] is True
|
||||
|
||||
# Update to False
|
||||
response = await async_client.put("/api/v1/settings/", json={"check_printer_firmware": False})
|
||||
assert response.status_code == 200
|
||||
assert response.json()["check_printer_firmware"] is False
|
||||
|
||||
# Verify persistence
|
||||
response = await async_client.get("/api/v1/settings/")
|
||||
assert response.json()["check_printer_firmware"] is False
|
||||
|
||||
# Update back to True
|
||||
response = await async_client.put("/api/v1/settings/", json={"check_printer_firmware": True})
|
||||
assert response.status_code == 200
|
||||
assert response.json()["check_printer_firmware"] is True
|
||||
|
||||
# ========================================================================
|
||||
# MQTT settings tests
|
||||
# ========================================================================
|
||||
|
||||
@@ -29,6 +29,7 @@ describe('Layout', () => {
|
||||
http.get('/api/v1/settings/', () => {
|
||||
return HttpResponse.json({
|
||||
check_updates: false,
|
||||
check_printer_firmware: false,
|
||||
auto_archive: true,
|
||||
});
|
||||
}),
|
||||
|
||||
@@ -105,6 +105,7 @@ describe('FileManagerPage', () => {
|
||||
http.get('/api/v1/settings/', () => {
|
||||
return HttpResponse.json({
|
||||
check_updates: false,
|
||||
check_printer_firmware: false,
|
||||
library_disk_warning_gb: 5,
|
||||
});
|
||||
}),
|
||||
|
||||
@@ -31,6 +31,7 @@ const mockSettings = {
|
||||
ha_url: '',
|
||||
ha_token: '',
|
||||
check_updates: false,
|
||||
check_printer_firmware: false,
|
||||
};
|
||||
|
||||
describe('SettingsPage', () => {
|
||||
@@ -124,6 +125,16 @@ describe('SettingsPage', () => {
|
||||
expect(screen.getByText('Appearance')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('shows updates section with firmware toggle', async () => {
|
||||
render(<SettingsPage />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Updates')).toBeInTheDocument();
|
||||
expect(screen.getByText('Check for updates')).toBeInTheDocument();
|
||||
expect(screen.getByText('Check printer firmware')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('tabs navigation', () => {
|
||||
|
||||
@@ -48,6 +48,7 @@ const mockArchives = [
|
||||
const mockSettings = {
|
||||
currency: '$',
|
||||
check_updates: false,
|
||||
check_printer_firmware: false,
|
||||
};
|
||||
|
||||
const mockFailureAnalysis = {
|
||||
|
||||
@@ -681,6 +681,7 @@ export interface AppSettings {
|
||||
energy_cost_per_kwh: number;
|
||||
energy_tracking_mode: 'print' | 'total';
|
||||
check_updates: boolean;
|
||||
check_printer_firmware: boolean;
|
||||
notification_language: string;
|
||||
// AMS threshold settings
|
||||
ams_humidity_good: number; // <= this is green
|
||||
|
||||
@@ -915,6 +915,7 @@ function PrinterCard({
|
||||
timeFormat = 'system',
|
||||
cameraViewMode = 'window',
|
||||
onOpenEmbeddedCamera,
|
||||
checkPrinterFirmware = true,
|
||||
}: {
|
||||
printer: Printer;
|
||||
hideIfDisconnected?: boolean;
|
||||
@@ -932,6 +933,7 @@ function PrinterCard({
|
||||
timeFormat?: 'system' | '12h' | '24h';
|
||||
cameraViewMode?: 'window' | 'embedded';
|
||||
onOpenEmbeddedCamera?: (printerId: number, printerName: string) => void;
|
||||
checkPrinterFirmware?: boolean;
|
||||
}) {
|
||||
const queryClient = useQueryClient();
|
||||
const navigate = useNavigate();
|
||||
@@ -992,12 +994,13 @@ function PrinterCard({
|
||||
refetchInterval: 30000, // Fallback polling, WebSocket handles real-time
|
||||
});
|
||||
|
||||
// Check for firmware updates (cached for 5 minutes)
|
||||
// Check for firmware updates (cached for 5 minutes, can be disabled in settings)
|
||||
const { data: firmwareInfo } = useQuery({
|
||||
queryKey: ['firmwareUpdate', printer.id],
|
||||
queryFn: () => firmwareApi.checkPrinterUpdate(printer.id),
|
||||
staleTime: 5 * 60 * 1000,
|
||||
refetchInterval: 5 * 60 * 1000,
|
||||
enabled: checkPrinterFirmware,
|
||||
});
|
||||
|
||||
// Collect unique tray_info_idx values for cloud filament info lookup
|
||||
@@ -4648,6 +4651,7 @@ export function PrintersPage() {
|
||||
timeFormat={settings?.time_format || 'system'}
|
||||
cameraViewMode={settings?.camera_view_mode || 'window'}
|
||||
onOpenEmbeddedCamera={(id, name) => setEmbeddedCameraPrinters(prev => new Map(prev).set(id, { id, name }))}
|
||||
checkPrinterFirmware={settings?.check_printer_firmware !== false}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
@@ -4676,6 +4680,7 @@ export function PrintersPage() {
|
||||
timeFormat={settings?.time_format || 'system'}
|
||||
cameraViewMode={settings?.camera_view_mode || 'window'}
|
||||
onOpenEmbeddedCamera={(id, name) => setEmbeddedCameraPrinters(prev => new Map(prev).set(id, { id, name }))}
|
||||
checkPrinterFirmware={settings?.check_printer_firmware !== false}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -407,6 +407,7 @@ export function SettingsPage() {
|
||||
settings.energy_cost_per_kwh !== localSettings.energy_cost_per_kwh ||
|
||||
settings.energy_tracking_mode !== localSettings.energy_tracking_mode ||
|
||||
settings.check_updates !== localSettings.check_updates ||
|
||||
(settings.check_printer_firmware ?? true) !== (localSettings.check_printer_firmware ?? true) ||
|
||||
settings.notification_language !== localSettings.notification_language ||
|
||||
settings.ams_humidity_good !== localSettings.ams_humidity_good ||
|
||||
settings.ams_humidity_fair !== localSettings.ams_humidity_fair ||
|
||||
@@ -469,6 +470,7 @@ export function SettingsPage() {
|
||||
energy_cost_per_kwh: localSettings.energy_cost_per_kwh,
|
||||
energy_tracking_mode: localSettings.energy_tracking_mode,
|
||||
check_updates: localSettings.check_updates,
|
||||
check_printer_firmware: localSettings.check_printer_firmware,
|
||||
notification_language: localSettings.notification_language,
|
||||
ams_humidity_good: localSettings.ams_humidity_good,
|
||||
ams_humidity_fair: localSettings.ams_humidity_fair,
|
||||
@@ -1296,6 +1298,23 @@ export function SettingsPage() {
|
||||
<div className="w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green"></div>
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-white">Check printer firmware</p>
|
||||
<p className="text-sm text-bambu-gray">
|
||||
Check for printer firmware updates from Bambu Lab
|
||||
</p>
|
||||
</div>
|
||||
<label className="relative inline-flex items-center cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={localSettings.check_printer_firmware ?? true}
|
||||
onChange={(e) => updateSetting('check_printer_firmware', e.target.checked)}
|
||||
className="sr-only peer"
|
||||
/>
|
||||
<div className="w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green"></div>
|
||||
</label>
|
||||
</div>
|
||||
<div className="border-t border-bambu-dark-tertiary pt-4">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<div>
|
||||
|
||||
File diff suppressed because one or more lines are too long
+1
-1
@@ -23,7 +23,7 @@
|
||||
|
||||
<!-- Splash screens for iOS -->
|
||||
<link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
|
||||
<script type="module" crossorigin src="/assets/index-abyjQYWw.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-CKmo1TxA.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-DFuUL8IF.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Reference in New Issue
Block a user