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
This commit is contained in:
maziggy
2026-01-31 12:59:45 +01:00
parent 29bede21b8
commit 428f54a68d
3 changed files with 18 additions and 10 deletions
+4
View File
@@ -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
View File
@@ -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
View File
@@ -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)