utp_service/backend/app/models/device.py
2026-04-07 11:55:28 +03:00

71 lines
3 KiB
Python

from datetime import datetime
from typing import Optional
from sqlalchemy import Boolean, DateTime, ForeignKey, Integer, String, Text
from sqlalchemy.dialects.postgresql import ARRAY, JSONB
from sqlalchemy.orm import Mapped, mapped_column, relationship
from .base import Base, TimestampMixin
DEVICE_CATEGORIES = ("raspberry", "mikrotik", "camera", "embedded", "server", "other")
DEVICE_ROLES = ("entry", "exit", "server", "nvr", "switch", "other")
DEVICE_STATUSES = ("online", "offline", "unknown")
DEVICE_SOURCES = ("auto_sync", "manual", "csv_import", "sheets_sync")
class Device(Base, TimestampMixin):
__tablename__ = "devices"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
object_id: Mapped[int] = mapped_column(
Integer,
ForeignKey("objects.id", ondelete="RESTRICT"),
nullable=False,
index=True,
)
ip: Mapped[str] = mapped_column(String(45), nullable=False)
hostname: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
mac: Mapped[Optional[str]] = mapped_column(String(17), nullable=True)
# Classification
category: Mapped[str] = mapped_column(String(20), nullable=False, default="other")
role: Mapped[str] = mapped_column(String(20), nullable=False, default="other")
model: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
firmware_version: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
# Source tracking
source: Mapped[str] = mapped_column(String(20), nullable=False, default="manual")
external_id: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
# SSH overrides (NULL = use object defaults)
ssh_user_override: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
ssh_pass_override_enc: Mapped[Optional[str]] = mapped_column(String(500), nullable=True)
ssh_port_override: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
# Device-specific metadata (Mikrotik API port, RTSP URL, etc.)
device_meta: Mapped[dict] = mapped_column(JSONB, nullable=False, default=dict)
# Capabilities populated by drivers
capabilities: Mapped[list[str]] = mapped_column(
ARRAY(String), nullable=False, default=list
)
# Monitoring
monitor_enabled: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
last_seen: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
last_ping_ms: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
status: Mapped[str] = mapped_column(String(20), nullable=False, default="unknown")
rack_id: Mapped[Optional[int]] = mapped_column(
Integer,
ForeignKey("racks.id", ondelete="SET NULL"),
nullable=True,
index=True,
)
notes: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
is_active: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
object: Mapped["Object"] = relationship("Object", back_populates="devices")
rack: Mapped[Optional["Rack"]] = relationship("Rack", back_populates="devices")