config.py 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. from dataclasses import dataclass, field
  2. from pathlib import Path
  3. PROJECT_ROOT = Path(__file__).resolve().parents[2]
  4. @dataclass(frozen=True)
  5. class AppSettings:
  6. """FastAPI 基础配置。"""
  7. title: str = "Raspberry Pi Camera API"
  8. version: str = "0.1.0"
  9. description: str = "用于树莓派相机抓拍的 FastAPI 服务。"
  10. host: str = "0.0.0.0"
  11. port: int = 8002
  12. @dataclass(frozen=True)
  13. class CameraSettings:
  14. """树莓派相机配置。"""
  15. camera_index: int = 0
  16. width: int = 2048
  17. height: int = 2048
  18. frame_format: str = "RGB888"
  19. jpeg_quality: int = 95
  20. warmup_seconds: float = 0.05
  21. enable_continuous_autofocus: bool = True
  22. enable_auto_white_balance: bool = True
  23. @dataclass(frozen=True)
  24. class MqttSettings:
  25. """MQTT 配置。"""
  26. broker: str = "192.168.77.132"
  27. port: int = 1883
  28. keep_alive_interval: int = 60
  29. client_id_prefix: str = "arm_camera_api_"
  30. request_timeout_seconds: float = 40.0
  31. connect_timeout_seconds: float = 5.0
  32. default_cycles: int = 1
  33. command_topic: str = "arm_card_dealer/command"
  34. camera_response_topic: str = "arm_card_dealer/camera/response"
  35. status_topic: str = "arm_card_dealer/status"
  36. error_topic: str = "arm_card_dealer/error"
  37. camera_command_topic: str = "arm_card_dealer/camera/command"
  38. @dataclass(frozen=True)
  39. class StaticSettings:
  40. """静态目录配置。"""
  41. root_dir: Path = field(default_factory=lambda: PROJECT_ROOT / "static")
  42. capture_dir_name: str = "captures"
  43. front_filename: str = "1.jpg"
  44. back_filename: str = "2.jpg"
  45. index_filename: str = "index.html"
  46. @property
  47. def capture_dir(self) -> Path:
  48. return self.root_dir / self.capture_dir_name
  49. @property
  50. def front_image_path(self) -> Path:
  51. return self.capture_dir / self.front_filename
  52. @property
  53. def back_image_path(self) -> Path:
  54. return self.capture_dir / self.back_filename
  55. @property
  56. def front_relative_path(self) -> Path:
  57. return Path(self.capture_dir_name) / self.front_filename
  58. @property
  59. def back_relative_path(self) -> Path:
  60. return Path(self.capture_dir_name) / self.back_filename
  61. @property
  62. def index_path(self) -> Path:
  63. return self.root_dir / self.index_filename
  64. def ensure_directories(self) -> None:
  65. self.capture_dir.mkdir(parents=True, exist_ok=True)
  66. @dataclass(frozen=True)
  67. class Settings:
  68. """项目总配置。"""
  69. app: AppSettings = field(default_factory=AppSettings)
  70. camera: CameraSettings = field(default_factory=CameraSettings)
  71. mqtt: MqttSettings = field(default_factory=MqttSettings)
  72. static: StaticSettings = field(default_factory=StaticSettings)
  73. settings = Settings()