smart_plug.py 4.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. from datetime import datetime
  2. from sqlalchemy import Boolean, DateTime, Float, ForeignKey, Integer, String, func
  3. from sqlalchemy.orm import Mapped, mapped_column, relationship
  4. from backend.app.core.database import Base
  5. class SmartPlug(Base):
  6. """Smart plug for printer power control (Tasmota or Home Assistant)."""
  7. __tablename__ = "smart_plugs"
  8. id: Mapped[int] = mapped_column(primary_key=True)
  9. name: Mapped[str] = mapped_column(String(100))
  10. ip_address: Mapped[str | None] = mapped_column(String(45), nullable=True) # IPv4/IPv6 (required for Tasmota)
  11. # Plug type: "tasmota" (default) or "homeassistant"
  12. plug_type: Mapped[str] = mapped_column(String(20), default="tasmota")
  13. # Home Assistant entity ID (e.g., "switch.printer_plug")
  14. ha_entity_id: Mapped[str | None] = mapped_column(String(100), nullable=True)
  15. # Home Assistant energy sensor entities (optional, for separate energy sensors)
  16. ha_power_entity: Mapped[str | None] = mapped_column(String(100), nullable=True) # sensor.xxx_power
  17. ha_energy_today_entity: Mapped[str | None] = mapped_column(String(100), nullable=True) # sensor.xxx_today
  18. ha_energy_total_entity: Mapped[str | None] = mapped_column(String(100), nullable=True) # sensor.xxx_total
  19. # Link to printer (scripts can coexist with regular plugs for multi-device control)
  20. printer_id: Mapped[int | None] = mapped_column(ForeignKey("printers.id", ondelete="SET NULL"), nullable=True)
  21. # Automation settings
  22. enabled: Mapped[bool] = mapped_column(Boolean, default=True)
  23. auto_on: Mapped[bool] = mapped_column(Boolean, default=True) # Turn on at print start
  24. auto_off: Mapped[bool] = mapped_column(Boolean, default=True) # Turn off at print complete/fail
  25. # Turn-off delay mode: "time" or "temperature"
  26. off_delay_mode: Mapped[str] = mapped_column(String(20), default="time")
  27. off_delay_minutes: Mapped[int] = mapped_column(Integer, default=5) # For time mode
  28. off_temp_threshold: Mapped[int] = mapped_column(Integer, default=70) # For temp mode (°C)
  29. # Optional auth (some Tasmota configs require it)
  30. username: Mapped[str | None] = mapped_column(String(50), nullable=True)
  31. password: Mapped[str | None] = mapped_column(String(100), nullable=True)
  32. # Power alerts
  33. power_alert_enabled: Mapped[bool] = mapped_column(Boolean, default=False)
  34. power_alert_high: Mapped[float | None] = mapped_column(Float, nullable=True) # Alert when power > this (watts)
  35. power_alert_low: Mapped[float | None] = mapped_column(Float, nullable=True) # Alert when power < this (watts)
  36. power_alert_last_triggered: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) # Cooldown tracking
  37. # Schedule (time-based on/off)
  38. schedule_enabled: Mapped[bool] = mapped_column(Boolean, default=False)
  39. schedule_on_time: Mapped[str | None] = mapped_column(String(5), nullable=True) # "HH:MM" format
  40. schedule_off_time: Mapped[str | None] = mapped_column(String(5), nullable=True) # "HH:MM" format
  41. # Visibility options
  42. show_in_switchbar: Mapped[bool] = mapped_column(Boolean, default=False)
  43. show_on_printer_card: Mapped[bool] = mapped_column(Boolean, default=True) # For scripts: show on printer card
  44. # Status tracking
  45. last_state: Mapped[str | None] = mapped_column(String(10), nullable=True) # "ON"/"OFF"
  46. last_checked: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
  47. auto_off_executed: Mapped[bool] = mapped_column(Boolean, default=False) # True when auto-off was triggered
  48. auto_off_pending: Mapped[bool] = mapped_column(Boolean, default=False) # True when waiting for cooldown
  49. auto_off_pending_since: Mapped[datetime | None] = mapped_column(
  50. DateTime, nullable=True
  51. ) # When auto-off was scheduled
  52. # Timestamps
  53. created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
  54. updated_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), onupdate=func.now())
  55. # Relationship
  56. printer: Mapped["Printer"] = relationship(back_populates="smart_plug")
  57. from backend.app.models.printer import Printer # noqa: E402