mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-09 07:25:44 +02:00
A printer kept dark between uses showed a black live view and sent black notification photos (#1655). Settings → Camera can turn the light on for all printers or for selected ones, for the live view, notification photos, the finish photo and the snapshot API that Home Assistant uses, and turns it off 15 seconds after the last use. It only turns off a light it turned on, and switching the light by hand hands it back. Snapshots wait an adjustable delay after the light comes on. Timelapse, the Obico check and the in-print frame bank don't switch it, since they would make it flash. The camera card no longer lists every printer: external cameras are added from a searchable printer picker and only those printers are listed, so large farms get a short page.
78 lines
4.8 KiB
Python
78 lines
4.8 KiB
Python
from datetime import datetime
|
|
|
|
from sqlalchemy import Boolean, DateTime, Float, String, func
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from backend.app.core.database import Base
|
|
|
|
|
|
class Printer(Base):
|
|
__tablename__ = "printers"
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
name: Mapped[str] = mapped_column(String(100))
|
|
serial_number: Mapped[str] = mapped_column(String(50), unique=True)
|
|
ip_address: Mapped[str] = mapped_column(String(253))
|
|
access_code: Mapped[str] = mapped_column(String(20))
|
|
model: Mapped[str | None] = mapped_column(String(50))
|
|
location: Mapped[str | None] = mapped_column(String(100)) # Group/location name
|
|
nozzle_count: Mapped[int] = mapped_column(default=1) # 1 or 2, auto-detected from MQTT
|
|
is_active: Mapped[bool] = mapped_column(Boolean, default=True)
|
|
auto_archive: Mapped[bool] = mapped_column(Boolean, default=True)
|
|
print_hours_offset: Mapped[float] = mapped_column(Float, default=0.0) # Baseline hours to add
|
|
runtime_seconds: Mapped[int] = mapped_column(
|
|
default=0
|
|
) # Accumulated active runtime (RUNNING state only — see #1521)
|
|
last_runtime_update: Mapped[datetime | None] = mapped_column(
|
|
DateTime, nullable=True
|
|
) # Last time runtime was updated
|
|
# External camera configuration
|
|
external_camera_url: Mapped[str | None] = mapped_column(String(500), nullable=True)
|
|
external_camera_type: Mapped[str | None] = mapped_column(String(20), nullable=True) # mjpeg, rtsp, snapshot
|
|
external_camera_enabled: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
# Optional single-frame snapshot URL — when set, used for snapshot / finish-photo
|
|
# / timelapse / plate-detect captures instead of opening the live stream and
|
|
# skipping a warm-up frame. Bypasses MJPEG warm-up issues on sources that
|
|
# expose a dedicated frame endpoint (e.g. go2rtc's /api/frame.jpeg). #1177.
|
|
external_camera_snapshot_url: Mapped[str | None] = mapped_column(String(500), nullable=True)
|
|
camera_rotation: Mapped[int] = mapped_column(default=0) # 0, 90, 180, 270 degrees
|
|
# Picked for the chamber light while the camera is in use (#1655). Only
|
|
# counts when the app setting camera_light_mode is "selected".
|
|
camera_light_auto: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
# Plate detection - check if build plate is empty before starting print
|
|
plate_detection_enabled: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
# ROI for plate detection (percentages: 0.0-1.0)
|
|
plate_detection_roi_x: Mapped[float | None] = mapped_column(Float, nullable=True) # X start %
|
|
plate_detection_roi_y: Mapped[float | None] = mapped_column(Float, nullable=True) # Y start %
|
|
plate_detection_roi_w: Mapped[float | None] = mapped_column(Float, nullable=True) # Width %
|
|
plate_detection_roi_h: Mapped[float | None] = mapped_column(Float, nullable=True) # Height %
|
|
# Queue: True after a print finishes/fails, until user acknowledges the plate is cleared.
|
|
# Persisted so the gate survives crashes and power cycles (issue #961).
|
|
awaiting_plate_clear: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
|
updated_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), onupdate=func.now())
|
|
|
|
# Relationships
|
|
archives: Mapped[list["PrintArchive"]] = relationship(back_populates="printer", cascade="all, delete-orphan")
|
|
smart_plugs: Mapped[list["SmartPlug"]] = relationship(back_populates="printer")
|
|
notification_providers: Mapped[list["NotificationProvider"]] = relationship(back_populates="printer")
|
|
maintenance_items: Mapped[list["PrinterMaintenance"]] = relationship(
|
|
back_populates="printer", cascade="all, delete-orphan"
|
|
)
|
|
kprofile_notes: Mapped[list["KProfileNote"]] = relationship(back_populates="printer", cascade="all, delete-orphan")
|
|
ams_history: Mapped[list["AMSSensorHistory"]] = relationship(back_populates="printer", cascade="all, delete-orphan")
|
|
sensor_history: Mapped[list["PrinterSensorHistory"]] = relationship(
|
|
back_populates="printer", cascade="all, delete-orphan"
|
|
)
|
|
ha_sensors: Mapped[list["PrinterHASensor"]] = relationship(back_populates="printer", cascade="all, delete-orphan")
|
|
|
|
|
|
from backend.app.models.ams_history import AMSSensorHistory # noqa: E402
|
|
from backend.app.models.archive import PrintArchive # noqa: E402
|
|
from backend.app.models.kprofile_note import KProfileNote # noqa: E402
|
|
from backend.app.models.maintenance import PrinterMaintenance # noqa: E402
|
|
from backend.app.models.notification import NotificationProvider # noqa: E402
|
|
from backend.app.models.printer_ha_sensor import PrinterHASensor # noqa: E402
|
|
from backend.app.models.printer_sensor_history import PrinterSensorHistory # noqa: E402
|
|
from backend.app.models.smart_plug import SmartPlug # noqa: E402
|