Переглянути джерело

Fix Home Assistant smart plug auto-on for queued prints (Issue #200)

The print scheduler was hardcoded to use Tasmota service when powering
on printers for queued prints. Home Assistant plugs were not checked,
causing "Tasmota device not found" errors.

Changes:
- Make get_service_for_plug() public in smart_plug_manager
- Update print_scheduler to use smart_plug_manager.get_service_for_plug()
  instead of tasmota_service directly
- Fixes both _power_on_and_wait() and _power_off_if_needed() methods

Closes #200
maziggy 3 місяців тому
батько
коміт
428f54a68d

+ 4 - 0
CHANGELOG.md

@@ -157,6 +157,10 @@ All notable changes to Bambuddy will be documented in this file.
   - Tooltip shows full name on hover
 - **K-Profiles Backup Status** - Fixed GitHub backup settings showing incorrect printer connection count (e.g., "1/2 connected" when both printers are connected); now fetches status from API instead of relying on WebSocket cache
 - **GitHub Backup Timestamps** - Removed volatile timestamps from GitHub backup files so git diffs only show actual data changes
+- **Home Assistant Smart Plug Auto-On** - Fixed print scheduler only checking Tasmota plugs when powering on printers for queued prints (Issue #200):
+  - Home Assistant smart plugs now work with automatic printer power-on for scheduled queue jobs
+  - Previously only Tasmota plugs were checked, causing HA plugs to fail with "Tasmota device not found" error
+  - Both `_power_on_and_wait` and `_power_off_if_needed` now use the correct service based on plug type
 
 ### Maintenance
 - Upgraded vitest from 2.x to 3.x to resolve npm audit security vulnerabilities in dev dependencies

+ 8 - 4
backend/app/services/print_scheduler.py

@@ -17,7 +17,7 @@ from backend.app.models.smart_plug import SmartPlug
 from backend.app.services.bambu_ftp import delete_file_async, get_ftp_retry_settings, upload_file_async, with_ftp_retry
 from backend.app.services.notification_service import notification_service
 from backend.app.services.printer_manager import printer_manager
-from backend.app.services.tasmota import tasmota_service
+from backend.app.services.smart_plug_manager import smart_plug_manager
 from backend.app.utils.printer_models import normalize_printer_model
 
 logger = logging.getLogger(__name__)
@@ -348,15 +348,18 @@ class PrintScheduler:
 
         Returns True if printer connected successfully within timeout.
         """
+        # Get the appropriate service for the plug type (Tasmota or Home Assistant)
+        service = await smart_plug_manager.get_service_for_plug(plug, db)
+
         # Check current plug state
-        status = await tasmota_service.get_status(plug)
+        status = await service.get_status(plug)
         if not status.get("reachable"):
             logger.warning(f"Smart plug '{plug.name}' is not reachable")
             return False
 
         # Turn on if not already on
         if status.get("state") != "ON":
-            success = await tasmota_service.turn_on(plug)
+            success = await service.turn_on(plug)
             if not success:
                 logger.warning(f"Failed to turn on smart plug '{plug.name}'")
                 return False
@@ -425,7 +428,8 @@ class PrintScheduler:
             # Wait for cooldown (up to 10 minutes)
             await printer_manager.wait_for_cooldown(item.printer_id, target_temp=50.0, timeout=600)
             logger.info(f"Auto-off: Powering off printer {item.printer_id}")
-            await tasmota_service.turn_off(plug)
+            service = await smart_plug_manager.get_service_for_plug(plug, db)
+            await service.turn_off(plug)
 
     async def _get_job_name(self, db: AsyncSession, item: PrintQueueItem) -> str:
         """Get a human-readable name for a queue item."""

+ 6 - 6
backend/app/services/smart_plug_manager.py

@@ -27,7 +27,7 @@ class SmartPlugManager:
         self._scheduler_task: asyncio.Task | None = None
         self._last_schedule_check: dict[int, str] = {}  # plug_id -> "HH:MM" last executed
 
-    async def _get_service_for_plug(self, plug: "SmartPlug", db: AsyncSession | None = None):
+    async def get_service_for_plug(self, plug: "SmartPlug", db: AsyncSession | None = None):
         """Get the appropriate service for the plug type.
 
         For HA plugs, configures the service with current settings from DB.
@@ -110,7 +110,7 @@ class SmartPlugManager:
             plugs = result.scalars().all()
 
             for plug in plugs:
-                service = await self._get_service_for_plug(plug, db)
+                service = await self.get_service_for_plug(plug, db)
 
                 # Check if we should turn on
                 if plug.schedule_on_time == current_time:
@@ -166,7 +166,7 @@ class SmartPlugManager:
 
         # Turn on the plug
         logger.info(f"Print started on printer {printer_id}, turning on plug '{plug.name}'")
-        service = await self._get_service_for_plug(plug, db)
+        service = await self.get_service_for_plug(plug, db)
         success = await service.turn_on(plug)
 
         if success:
@@ -261,7 +261,7 @@ class SmartPlugManager:
                     self.name = f"plug_{plug_id}"
 
             plug_info = PlugInfo()
-            service = await self._get_service_for_plug(plug_info)
+            service = await self.get_service_for_plug(plug_info)
             success = await service.turn_off(plug_info)
             logger.info(f"Turned off plug {plug_id} after time delay")
 
@@ -353,7 +353,7 @@ class SmartPlugManager:
                                 self.name = f"plug_{plug_id}"
 
                         plug_info = PlugInfo()
-                        service = await self._get_service_for_plug(plug_info)
+                        service = await self.get_service_for_plug(plug_info)
                         success = await service.turn_off(plug_info)
                         logger.info(
                             f"Turned off plug {plug_id} after nozzle temp dropped to "
@@ -474,7 +474,7 @@ class SmartPlugManager:
                         # For time mode, just turn off immediately since delay already passed
                         logger.info(f"Time-based auto-off was pending, turning off plug '{plug.name}' now")
 
-                        service = await self._get_service_for_plug(plug, db)
+                        service = await self.get_service_for_plug(plug, db)
                         success = await service.turn_off(plug)
                         if success:
                             await self._mark_auto_off_executed(plug.id)