Binds binary_sensor and reading-carrying sensor entities to a printer and
renders their state on its card, worded by Home Assistant's device_class.
Optional per-sensor alert condition drives a notification on the transition
into the alert state and an opt-in interlock that holds queued prints while
alerting -- a hold with a readable waiting_reason, never a failure, and only
ever on a sensor that was read successfully.
Sensors get their own table rather than a wider entity pattern on SmartPlug:
get_smart_plug_by_printer would otherwise hand the card's power button a door
contact to switch.
The hold is passed to the model matcher directly rather than merged into
busy_printers: _check_auto_drying reads that set as "is currently printing"
and would put an idle-but-held printer down the mid-print drying path.
The notification_providers migration spells its default FALSE, not 0 --
Postgres rejects an integer default for a boolean and _safe_execute swallows
the error.
When a print reaches a terminal state Bambuddy holds the queue until
someone confirms the build plate is clear. That gate was visible only in
the Web UI: the printer's own MQTT push reports nothing beyond RUNNING,
PAUSE, FAILED, FINISH and IDLE, so an external automation could not tell
"finished" from "finished and still waiting for a human".
The per-printer status topic now carries an awaiting_plate_clear field,
and every transition is additionally published on a new retained topic,
bambuddy/printers/{serial}/plate_clear. Retained, and published from the
flag itself rather than from printer telemetry: a subscriber learns the
state of every printer the moment it connects, and the state stays
correct after Auto Off powers a printer down - telemetry stops there,
which would otherwise leave the status topic frozen at false.
Publishing is edge-triggered. The queue clears the gate on every
dispatch whether or not it was up, and no subscriber should see a
"plate cleared" for a plate that was never dirty. Persistence and the
WebSocket broadcast stay unconditional; they are idempotent and predate
this.
A matching Plate Clear Required notification event was added, off by
default on every provider because it fires after every print at the
same moment as the print-complete alert. Only the rising edge notifies.
Acknowledging still goes through POST /printers/{id}/clear-plate.
Two tests in test_printer_manager_status_broadcast.py asserted
_schedule_async.call_count == 2 for the setter. The new emission makes
it three on a transition, so they now assert that the persist and
broadcast coroutines are actually scheduled - which is the contract
Translated in all locales; wiki updated. Covered by backend and
frontend tests.
The app was built dark-first, so hundreds of hardcoded Tailwind semantic
text/icon utilities at light shades (text-amber-400, text-blue-300, ...) had
no dark: variant. With darkMode:'class' they applied in light theme too,
producing washed-out text on pale tints and white cards — including the three
reported spots (AMS Drying banner, Archives no-3MF warning, debug-logging
banner). Give each a theme-aware pair: a darker readable shade in light theme
with the original pinned to dark:, so dark theme is unchanged. ~100 files.
The bambu-* CSS-variable palette (self-correcting) and the dark-only SpoolBuddy
kiosk are left untouched. Plain text-white is already theme-aware via the
existing index.css .text-white override, so it needed no changes.
Split Obico failure-detection dispatch out of the multiplexed
on_printer_error event onto its own on_ai_failure_detection event so
users can subscribe to AI alerts without also enabling HMS hardware-
error pages, and so the discoverable label "AI Failure Detection" is
what subscribes them rather than the unrelated "Printer Error" toggle.
New column on notification_providers (default False, branched
SQLite/Postgres migration), new notification_service.on_ai_failure_detection
method, new ai_failure_detection template, obico_actions._notify swap.
Frontend gets a summary badge, a toggle row with description, and ntfy
priority surfacing. 14 new tests pin the routing + the regression guard
("Printer Error" alone must NOT receive AI notifications now). 11 locales
covered.
Existing providers keep working: HMS hardware errors continue to ride
on_printer_error unchanged; users who want spaghetti alerts opt in via
the new toggle.
Notify users when the first layer finishes printing so they can check
adhesion remotely. Triggers once per print when layer 2 begins
(layer_num >= 2, capped at <= 5 to handle reconnects). Includes a
camera snapshot attachment. Adds the on_first_layer_complete toggle
to all notification providers, with backend/frontend/i18n support
across all 7 locales.
Replace all hardcoded English strings with t() translation calls across
9 components: SettingsPage, SmartPlugCard, AddSmartPlugModal,
SwitchbarPopover, NotificationProviderCard, AddNotificationModal,
NotificationTemplateEditor, NotificationLogViewer, GitHubBackupSettings,
and RestoreModal. Add ~600 new translation keys to all 7 locales
(en, de, ja, fr, it, pt-BR, zh-CN).
Notify users when the print bed cools below a configurable threshold
(default 35°C) after a print finishes, so they know when to remove parts.
- Backend: DB migration, model, schemas, notification template, service
method, background cooldown monitor (polls every 15s, 30min timeout)
- Frontend: event toggle in provider card/modal, threshold setting in
Settings > Notifications, i18n keys for all 5 locales
- Tests: 4 backend + 4 frontend tests
- Docs: README, website, wiki updated
Model-based queue assignment:
- Extract printer_model from sliced 3MF files during upload
- Display sliced-for model in archive view
- New queue mode: assign to "Any [Model]" instead of specific printer
- Scheduler auto-assigns to first idle printer of matching model
- Filament validation: only assign to printers with required filament types loaded
- Waiting reason display shows why jobs are waiting (e.g., "Waiting for filament: Printer1 (needs PLA)")
- "Waiting" status badge (purple) distinguishes from regular "Pending"
Queue notifications (7 new events):
- Job Added: When a job is added to queue
- Job Assigned: When a model-based job is assigned to a printer
- Job Started: When a queue job starts printing
- Job Waiting: When a job is waiting for filament (enabled by default)
- Job Skipped: When a job is skipped due to previous failure (enabled by default)
- Job Failed: When a job fails to start (enabled by default)
- Queue Complete: When all queued jobs finish
Backend changes:
- New columns: print_queue.target_model, print_queue.required_filament_types, print_queue.waiting_reason
- New columns: notification_providers.on_queue_job_* (7 event triggers)
- Notification templates for all queue events
- Scheduler validates filament compatibility before model-based assignment
- Queue API extracts filament types from 3MF when adding model-based items
- Local backup/restore includes queue notification settings
Frontend changes:
- TypeScript interfaces updated for new fields
- Queue page shows waiting reason and "Waiting" badge
- Notification settings includes "Print Queue" section with 7 toggles
Closes#162
Status badges (Connected/Offline, HMS errors, maintenance, success/failed)
were using bambu-green which follows the user's accent color theme. This
caused confusing UX - e.g., "Connected" appearing red with a red accent.
Added fixed semantic status colors that never change with theme:
- status-ok: #22c55e (green) - success, online, OK states
- status-error: #ef4444 (red) - failed, offline, error states
- status-warning: #f59e0b (amber) - warnings, pending states
Updated components:
- PrintersPage: connection badge, HMS errors, maintenance, WiFi signal
- SmartPlugCard/SwitchbarPopover: plug connectivity status
- StatsPage: success/failed counts, failure rate, time accuracy
- QueuePage: queue item statuses (pending, completed, failed)
- ArchivesPage: failed/aborted archive badge
- ProjectDetailPage: child status, timeline events, BOM checklist
- CompareArchivesModal: archive completion status
- NotificationProviderCard: last success/error status
Closes#136
Problem: The backend stores timestamps in UTC, but when sending them to the frontend without timezone indicators, JavaScript interprets them inconsistently. Users saw UTC times displayed directly instead of converted to their local timezone (e.g., America/New_York).
Solution implemented:
1. Created /frontend/src/utils/date.ts with utilities:
- parseUTCDate(dateStr) - Parses backend timestamps as UTC by appending 'Z' to strings without timezone indicators
- formatDate(dateStr, options) - Formats UTC timestamps to local date/time
- formatDateOnly(dateStr, options) - Formats UTC timestamps to local date-only
2. Updated 15 frontend files to use the new utilities:
- ArchivesPage.tsx - Archive cards and list view dates
- PrintersPage.tsx - Last print date
- SettingsPage.tsx - API key last used date
- QueuePage.tsx - Scheduled print times
- ProjectDetailPage.tsx - Due dates and timeline
- ProfilesPage.tsx - Relative time display
- CalendarView.tsx - Calendar grouping by local date
- NotificationLogViewer.tsx - Log timestamps
- NotificationProviderCard.tsx - Last success date
- AMSHistoryModal.tsx - Chart data timestamps
- FilamentTrends.tsx - Usage data grouping
- PrinterQueueWidget.tsx - Queue item dates
- Separate AMS and AMS-HT notification switches (one per device type)
- Fix notification variables not showing (duration, filament, estimated_time)
- Add fallback values for empty notification variables ("Unknown" instead of blank)
Settings:
- Fix API keys badge count only showing after visiting tab
- Move External Links card to third column above Updates
- Add Release Notes modal for viewing full notes before updating
Statistics:
- Fix filament usage trends not showing (wrong API parameters)
- Move dashboard controls (Hidden, Reset Layout) to header row
- Remove duplicate Reset Layout button
Camera:
- Fix ffmpeg processes not killed when closing webcam window
- Add /camera/stop endpoint with POST support for sendBeacon
- Track active streams and proper cleanup on disconnect