printer.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. from datetime import datetime
  2. from pydantic import BaseModel, Field
  3. class PrinterBase(BaseModel):
  4. name: str = Field(..., min_length=1, max_length=100)
  5. serial_number: str = Field(..., min_length=1, max_length=50)
  6. ip_address: str = Field(..., pattern=r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$")
  7. access_code: str = Field(..., min_length=1, max_length=20)
  8. model: str | None = None
  9. location: str | None = None # Group/location name
  10. auto_archive: bool = True
  11. external_camera_url: str | None = None
  12. external_camera_type: str | None = None # "mjpeg", "rtsp", "snapshot"
  13. external_camera_enabled: bool = False
  14. class PrinterCreate(PrinterBase):
  15. pass
  16. class PrinterUpdate(BaseModel):
  17. name: str | None = None
  18. ip_address: str | None = None
  19. access_code: str | None = None
  20. model: str | None = None
  21. location: str | None = None
  22. is_active: bool | None = None
  23. auto_archive: bool | None = None
  24. print_hours_offset: float | None = None
  25. external_camera_url: str | None = None
  26. external_camera_type: str | None = None
  27. external_camera_enabled: bool | None = None
  28. class PrinterResponse(PrinterBase):
  29. id: int
  30. is_active: bool
  31. nozzle_count: int = 1 # 1 or 2, auto-detected from MQTT
  32. print_hours_offset: float = 0.0
  33. external_camera_url: str | None = None
  34. external_camera_type: str | None = None
  35. external_camera_enabled: bool = False
  36. created_at: datetime
  37. updated_at: datetime
  38. class Config:
  39. from_attributes = True
  40. class HMSErrorResponse(BaseModel):
  41. code: str
  42. attr: int = 0 # Attribute value for constructing wiki URL
  43. module: int
  44. severity: int # 1=fatal, 2=serious, 3=common, 4=info
  45. class AMSTray(BaseModel):
  46. id: int
  47. tray_color: str | None = None
  48. tray_type: str | None = None
  49. tray_sub_brands: str | None = None # Full name like "PLA Basic", "PETG HF"
  50. tray_id_name: str | None = None # Bambu filament ID like "A00-Y2" (can decode to color)
  51. tray_info_idx: str | None = None # Filament preset ID like "GFA00"
  52. remain: int = 0
  53. k: float | None = None # Pressure advance value (from tray or K-profile lookup)
  54. cali_idx: int | None = None # Calibration index for K-profile lookup
  55. tag_uid: str | None = None # RFID tag UID (any tag)
  56. tray_uuid: str | None = None # Bambu Lab spool UUID (32-char hex)
  57. nozzle_temp_min: int | None = None # Min nozzle temperature
  58. nozzle_temp_max: int | None = None # Max nozzle temperature
  59. class AMSUnit(BaseModel):
  60. id: int
  61. humidity: int | None = None
  62. temp: float | None = None
  63. is_ams_ht: bool = False # True for AMS-HT (single spool), False for regular AMS (4 spools)
  64. tray: list[AMSTray] = []
  65. class NozzleInfoResponse(BaseModel):
  66. nozzle_type: str = "" # "stainless_steel" or "hardened_steel"
  67. nozzle_diameter: str = "" # e.g., "0.4"
  68. class PrintOptionsResponse(BaseModel):
  69. """AI detection and print options from xcam data."""
  70. # Core AI detectors
  71. spaghetti_detector: bool = False
  72. print_halt: bool = False
  73. halt_print_sensitivity: str = "medium" # Spaghetti sensitivity
  74. first_layer_inspector: bool = False
  75. printing_monitor: bool = False
  76. buildplate_marker_detector: bool = False
  77. allow_skip_parts: bool = False
  78. # Additional AI detectors (decoded from cfg bitmask)
  79. nozzle_clumping_detector: bool = True
  80. nozzle_clumping_sensitivity: str = "medium"
  81. pileup_detector: bool = True
  82. pileup_sensitivity: str = "medium"
  83. airprint_detector: bool = True
  84. airprint_sensitivity: str = "medium"
  85. auto_recovery_step_loss: bool = True
  86. filament_tangle_detect: bool = False
  87. class PrinterStatus(BaseModel):
  88. id: int
  89. name: str
  90. connected: bool
  91. state: str | None = None
  92. current_print: str | None = None
  93. subtask_name: str | None = None
  94. gcode_file: str | None = None
  95. progress: float | None = None
  96. remaining_time: int | None = None
  97. layer_num: int | None = None
  98. total_layers: int | None = None
  99. temperatures: dict | None = None
  100. cover_url: str | None = None
  101. hms_errors: list[HMSErrorResponse] = []
  102. ams: list[AMSUnit] = []
  103. ams_exists: bool = False
  104. vt_tray: AMSTray | None = None # Virtual tray / external spool
  105. sdcard: bool = False # SD card inserted
  106. store_to_sdcard: bool = False # Store sent files on SD card
  107. timelapse: bool = False # Timelapse recording active
  108. ipcam: bool = False # Live view enabled
  109. wifi_signal: int | None = None # WiFi signal strength in dBm
  110. nozzles: list[NozzleInfoResponse] = [] # Nozzle hardware info (index 0=left/primary, 1=right)
  111. print_options: PrintOptionsResponse | None = None # AI detection and print options
  112. # Calibration stage tracking
  113. stg_cur: int = -1 # Current stage number (-1 = not calibrating)
  114. stg_cur_name: str | None = None # Human-readable current stage name
  115. stg: list[int] = [] # List of stage numbers in calibration sequence
  116. # Air conditioning mode (0=cooling, 1=heating)
  117. airduct_mode: int = 0
  118. # Print speed level (1=silent, 2=standard, 3=sport, 4=ludicrous)
  119. speed_level: int = 2
  120. # Chamber light on/off
  121. chamber_light: bool = False
  122. # Active extruder for dual nozzle (0=right, 1=left)
  123. active_extruder: int = 0
  124. # AMS mapping for dual nozzle: which AMS is connected to which nozzle
  125. ams_mapping: list[int] = []
  126. # Per-AMS extruder map: {ams_id: extruder_id} where 0=right, 1=left
  127. ams_extruder_map: dict[str, int] = {}
  128. # Currently loaded tray (global ID): 254 = external spool, 255 = no filament
  129. tray_now: int = 255
  130. # AMS status for filament change tracking
  131. # Main status: 0=idle, 1=filament_change, 2=rfid_identifying, 3=assist, 4=calibration
  132. ams_status_main: int = 0
  133. # Sub status: specific step within filament change (when main=1)
  134. # Known values: 4=retraction, 6=load verification, 7=purge
  135. ams_status_sub: int = 0
  136. # mc_print_sub_stage - filament change step indicator used by OrcaSlicer/BambuStudio
  137. mc_print_sub_stage: int = 0
  138. # Timestamp of last AMS data update (for RFID refresh detection)
  139. last_ams_update: float = 0.0
  140. # Number of printable objects in current print (for skip objects feature)
  141. printable_objects_count: int = 0
  142. # Fan speeds (0-100 percentage, None if not available for this model)
  143. cooling_fan_speed: int | None = None # Part cooling fan
  144. big_fan1_speed: int | None = None # Auxiliary fan
  145. big_fan2_speed: int | None = None # Chamber/exhaust fan
  146. heatbreak_fan_speed: int | None = None # Hotend heatbreak fan
  147. # Firmware version (from info.module[name="ota"].sw_ver)
  148. firmware_version: str | None = None