From 0664c96cbf48cb6c5da6f1b7ca50e0fa95a9fa1f Mon Sep 17 00:00:00 2001 From: maziggy Date: Sat, 31 Jan 2026 15:09:23 +0100 Subject: [PATCH] Misc merge fixes --- backend/app/core/database.py | 73 ++++++++++++++++++++++++++++++++ backend/app/models/smart_plug.py | 3 ++ 2 files changed, 76 insertions(+) diff --git a/backend/app/core/database.py b/backend/app/core/database.py index 9b3c6c299..2f74cd8c6 100644 --- a/backend/app/core/database.py +++ b/backend/app/core/database.py @@ -760,6 +760,79 @@ async def run_migrations(conn): except Exception: pass + # Migration: Remove UNIQUE constraint from smart_plugs.printer_id + # This allows HA scripts to coexist with regular plugs (scripts are for multi-device control) + # SQLite requires table recreation to drop constraints + try: + # Check if we need to migrate (if UNIQUE constraint exists) + result = await conn.execute(text("SELECT sql FROM sqlite_master WHERE type='table' AND name='smart_plugs'")) + row = result.fetchone() + if row and "printer_id INTEGER UNIQUE" in (row[0] or ""): + # Create new table without UNIQUE constraint on printer_id + await conn.execute( + text(""" + CREATE TABLE smart_plugs_temp ( + id INTEGER PRIMARY KEY, + name VARCHAR(100) NOT NULL, + ip_address VARCHAR(45), + plug_type VARCHAR(20) DEFAULT 'tasmota', + ha_entity_id VARCHAR(100), + ha_power_entity VARCHAR(100), + ha_energy_today_entity VARCHAR(100), + ha_energy_total_entity VARCHAR(100), + printer_id INTEGER REFERENCES printers(id) ON DELETE SET NULL, + enabled BOOLEAN NOT NULL DEFAULT 1, + auto_on BOOLEAN NOT NULL DEFAULT 1, + auto_off BOOLEAN NOT NULL DEFAULT 1, + off_delay_mode VARCHAR(20) NOT NULL DEFAULT 'time', + off_delay_minutes INTEGER NOT NULL DEFAULT 5, + off_temp_threshold INTEGER NOT NULL DEFAULT 70, + username VARCHAR(50), + password VARCHAR(100), + power_alert_enabled BOOLEAN NOT NULL DEFAULT 0, + power_alert_high FLOAT, + power_alert_low FLOAT, + power_alert_last_triggered DATETIME, + schedule_enabled BOOLEAN NOT NULL DEFAULT 0, + schedule_on_time VARCHAR(5), + schedule_off_time VARCHAR(5), + show_in_switchbar BOOLEAN DEFAULT 0, + last_state VARCHAR(10), + last_checked DATETIME, + auto_off_executed BOOLEAN NOT NULL DEFAULT 0, + auto_off_pending BOOLEAN DEFAULT 0, + auto_off_pending_since DATETIME, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL + ) + """) + ) + # Copy data + await conn.execute( + text(""" + INSERT INTO smart_plugs_temp + SELECT id, name, ip_address, plug_type, ha_entity_id, ha_power_entity, + ha_energy_today_entity, ha_energy_total_entity, printer_id, enabled, + auto_on, auto_off, off_delay_mode, off_delay_minutes, off_temp_threshold, + username, password, power_alert_enabled, power_alert_high, power_alert_low, + power_alert_last_triggered, schedule_enabled, schedule_on_time, schedule_off_time, + show_in_switchbar, last_state, last_checked, auto_off_executed, + auto_off_pending, auto_off_pending_since, created_at, updated_at + FROM smart_plugs + """) + ) + # Drop old table and rename new one + await conn.execute(text("DROP TABLE smart_plugs")) + await conn.execute(text("ALTER TABLE smart_plugs_temp RENAME TO smart_plugs")) + except Exception: + pass + + # Migration: Add show_on_printer_card column to smart_plugs + try: + await conn.execute(text("ALTER TABLE smart_plugs ADD COLUMN show_on_printer_card BOOLEAN DEFAULT 1")) + except Exception: + pass + # Migration: Add MQTT smart plug fields (legacy) try: await conn.execute(text("ALTER TABLE smart_plugs ADD COLUMN mqtt_topic VARCHAR(200)")) diff --git a/backend/app/models/smart_plug.py b/backend/app/models/smart_plug.py index 3bcc3b1ee..1d9160ef9 100644 --- a/backend/app/models/smart_plug.py +++ b/backend/app/models/smart_plug.py @@ -83,6 +83,9 @@ class SmartPlug(Base): # Switchbar visibility show_in_switchbar: Mapped[bool] = mapped_column(Boolean, default=False) + # Printer card visibility (for scripts) + show_on_printer_card: Mapped[bool] = mapped_column(Boolean, default=True) + # Status tracking last_state: Mapped[str | None] = mapped_column(String(10), nullable=True) # "ON"/"OFF" last_checked: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)