Browse Source

Fix HMS notifications firing for unknown/phantom error codes

  Printers send many undocumented HMS codes (e.g. 0501_0002, 0501_0004,
  0300_0001) that don't correspond to real errors — calibration status,
  firmware state, etc. The frontend already filters these out (only shows
  codes in ERROR_DESCRIPTIONS), but the backend notified for all codes
  with severity >= 2, causing spurious email/push notifications on every
  backend restart when a printer has active phantom codes.

  Flip the logic: only send notifications for HMS codes with a known
  description in the backend's HMS_ERROR_DESCRIPTIONS dictionary. Also
  fix the log message to report the actual number of notifications sent,
  not the pre-filter count.
maziggy 2 months ago
parent
commit
e314305623
2 changed files with 14 additions and 11 deletions
  1. 1 0
      CHANGELOG.md
  2. 13 11
      backend/app/main.py

+ 1 - 0
CHANGELOG.md

@@ -37,6 +37,7 @@ All notable changes to Bambuddy will be documented in this file.
 - **Force Color Match Toggle Click Target Too Large** ([#688](https://github.com/maziggy/bambuddy/issues/688)) — In the Schedule Print modal, clicking anywhere on the "Force color match" row toggled the checkbox, not just the checkbox and its label. The click target now covers only the checkbox, icon, and label text. Reported by @aneopsy.
 - **HA Switch Badge Always Sends Turn On Instead of Toggle** — Clicking a non-script Home Assistant entity (switch, light, input_boolean) on the printer card always sent `turn_on`, which is a no-op when the switch is already on. Now sends `toggle` for non-script entities so the badge click actually toggles the switch state. Script entities still use `turn_on` (stateless trigger).
 - **Multiple Plugs Per Printer Crashes Auto-On/Off** — When multiple smart plugs were assigned to the same printer (e.g., a Tasmota plug + an HA switch), the auto-on/auto-off handler called `scalar_one_or_none()` which raises `MultipleResultsFound`. Now fetches all plugs and returns the main (non-script) power plug, matching the API route behavior.
+- **HMS Notifications for Unknown/Phantom Error Codes** — Printers send many undocumented or phantom HMS error codes that don't correspond to real errors (e.g. calibration status codes after firmware updates). These triggered email/push notifications even though the printer card correctly filtered them out. Flipped the notification logic from "notify all, suppress specific codes" to "only notify for errors with known descriptions", matching the frontend behavior. Also fixed the log message reporting incorrect notification counts.
 - **Debug Logging Endpoint 500 Error** — The `GET /api/v1/support/debug-logging` endpoint returned a 500 Internal Server Error when the database contained a timezone-aware timestamp written by a previous version. The duration calculation subtracted a timezone-aware datetime from a naive `datetime.now()`, raising `TypeError`. Now strips timezone info when reading the stored timestamp.
 - **Bed Cooled Notification Never Fires** ([#497](https://github.com/maziggy/bambuddy/issues/497)) — The bed cooldown monitor always timed out after 30 minutes without sending a notification. After print completion, P1S (and likely other models) sends partial MQTT status updates that don't include `bed_temper`, so the cached bed temperature stayed frozen at the end-of-print value and never dropped below the threshold. The monitor now sends periodic `pushall` commands to the printer to force fresh temperature data. Also added debug logging to the polling loop for future diagnostics.
 - **Notification Provider Missing Event Toggles on Create** ([#497](https://github.com/maziggy/bambuddy/issues/497)) — When creating a new notification provider, the `on_bed_cooled` toggle and all 7 queue event toggles (`on_queue_job_added`, `on_queue_job_assigned`, `on_queue_job_started`, `on_queue_job_waiting`, `on_queue_job_skipped`, `on_queue_job_failed`, `on_queue_completed`) were silently discarded. The create endpoint manually listed each field but omitted these 8 toggles, so they always defaulted to `false` regardless of user selection. Editing an existing provider worked correctly.

+ 13 - 11
backend/app/main.py

@@ -445,11 +445,9 @@ async def on_printer_status_change(printer_id: int, state: PrinterState):
         _last_progress_milestone[printer_id] = 0
         _first_layer_notified[printer_id] = False
 
-    # HMS error codes that should not trigger notifications.
-    # These are infrastructure/auth issues, not actionable print errors.
+    # HMS error codes that should not trigger notifications even though they
+    # have known descriptions (e.g. user-initiated actions, not real errors).
     _HMS_NOTIFICATION_SUPPRESS = {
-        "0500_0007",  # MQTT command verification failed (auth/bind issue, not a print error)
-        "0500_4001",  # Failed to connect to Bambu Cloud (network issue)
         "0500_400E",  # Printing was cancelled (user action, not an error)
     }
 
@@ -497,6 +495,7 @@ async def on_printer_status_change(printer_id: int, state: PrinterState):
                         printer_id, printer, logging.getLogger(__name__)
                     )
 
+                    sent_count = 0
                     for error in new_errors:
                         module_name = module_names.get(error.module, f"Module 0x{error.module:02X}")
                         # Build short code like "0700_8010"
@@ -505,21 +504,24 @@ async def on_printer_status_change(printer_id: int, state: PrinterState):
                         error_code_masked = error_code_int & 0xFFFF
                         short_code = f"{(error.attr >> 16) & 0xFFFF:04X}_{error_code_masked:04X}"
 
-                        if short_code in _HMS_NOTIFICATION_SUPPRESS:
+                        # Only notify for errors with known descriptions — printers
+                        # send many undocumented/phantom codes that aren't real errors.
+                        description = get_error_description(short_code)
+                        if not description or short_code in _HMS_NOTIFICATION_SUPPRESS:
                             continue
 
                         error_type = f"{module_name} Error"
-                        # Look up human-readable description
-                        description = get_error_description(short_code)
-                        error_detail = description if description else f"Error code: {short_code}"
+                        error_detail = description
 
                         await notification_service.on_printer_error(
                             printer_id, printer_name, error_type, db, error_detail, image_data=error_image_data
                         )
+                        sent_count += 1
 
-                    logging.getLogger(__name__).info(
-                        f"[HMS] Sent notification for {len(new_errors)} new error(s) on printer {printer_id}"
-                    )
+                    if sent_count:
+                        logging.getLogger(__name__).info(
+                            f"[HMS] Sent notification for {sent_count} error(s) on printer {printer_id}"
+                        )
 
                     # Also publish to MQTT relay
                     printer_info = printer_manager.get_printer(printer_id)