config_loader.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import configparser
  2. import re
  3. from .models import *
  4. def load_config(config_path: str) -> Config:
  5. cfg = configparser.ConfigParser()
  6. cfg.read(config_path, encoding='utf-8')
  7. config = Config()
  8. config.app_name = cfg.get("App", "name", fallback="钢包工位视频监测系统")
  9. config.copyright = cfg.get("App", "copyright", fallback="恒莱达")
  10. config.screen = cfg.getint("App", "screen", fallback=0)
  11. module_type_str = cfg.get("Hardware", "module_type", fallback="RFID")
  12. config.module_type = ModuleType.RFID if module_type_str == "RFID" else ModuleType.HD3200
  13. if cfg.has_section("Video"):
  14. config.video.rtsp_timeout = cfg.getfloat("Video", "rtsp_timeout", fallback=5.0)
  15. config.video.ratio_16_9 = cfg.getboolean("Video", "ratio_16_9", fallback=True)
  16. # RFID
  17. if config.module_type == ModuleType.RFID:
  18. config.rfid = SocketConfig(
  19. ip=cfg.get("RFID", "ip"),
  20. port=cfg.getint("RFID", "port"),
  21. stability_time=cfg.getint("RFID", "stability_time", fallback=20),
  22. stability_count=cfg.getint("RFID", "stability_count", fallback=3)
  23. )
  24. # Modbus
  25. if config.module_type == ModuleType.HD3200:
  26. config.modbus = ModbusConfig(
  27. ip=cfg.get("Modbus", "ip"),
  28. port=cfg.getint("Modbus", "port", fallback=502),
  29. frequency=cfg.getint("Modbus", "frequency", fallback=100),
  30. stability_count=cfg.getint("Modbus", "stability_count", fallback=3)
  31. )
  32. # AI
  33. config.ai.enabled = cfg.getboolean("AI", "enabled", fallback=False)
  34. config.ai.tts_enabled = cfg.getboolean("AI", "tts_enabled", fallback=False)
  35. config.ai.debug_trace = cfg.getboolean("AI", "debug_trace", fallback=True)
  36. config.ai.offset_ratio_tolerance = cfg.getfloat("AI", "offset_ratio_tolerance", fallback=0.25)
  37. config.ai.ready_debounce = cfg.getint("AI", "ready_debounce", fallback=3)
  38. config.ai.auto_calib_ready_frames = cfg.getint("AI", "auto_calib_ready_frames", fallback=3)
  39. config.ai.auto_calib_duration_secs = cfg.getfloat("AI", "auto_calib_duration_secs", fallback=1.0)
  40. config.ai.auto_calib_min_samples = cfg.getint("AI", "auto_calib_min_samples", fallback=2)
  41. # AI Modules (自动扫描 AI:N 段)
  42. for section in sorted(
  43. (s for s in cfg.sections() if re.match(r'^AI:\d+$', s)),
  44. key=lambda s: int(s.split(':')[1])
  45. ):
  46. idx = int(section.split(':')[1])
  47. topics_str = cfg.get(section, "topics", fallback="")
  48. config.ai_modules.append(AIModuleModel(
  49. id=idx,
  50. broker=cfg.get(section, "broker"),
  51. port=cfg.getint(section, "port", fallback=1883),
  52. topics=[t.strip() for t in topics_str.split('\n') if t.strip()]
  53. ))
  54. # Buckets (自动扫描 Bucket:N 段)
  55. bucket_sections = sorted(
  56. (s for s in cfg.sections() if re.match(r'^Bucket:\d+$', s)),
  57. key=lambda s: int(s.split(':')[1])
  58. )
  59. for section in bucket_sections:
  60. bucket = BucketModel(
  61. id=cfg.getint(section, "id"),
  62. description=cfg.get(section, "description"),
  63. code_x=cfg.get(section, "code_x"),
  64. code_y=cfg.get(section, "code_y", fallback=""),
  65. ai_module_id=cfg.getint(section, "ai_module", fallback=None),
  66. hook_lug_x_offset_ratio_left=cfg.getfloat(section, "hook_lug_x_offset_ratio_left", fallback=None),
  67. hook_lug_y_offset_ratio_left=cfg.getfloat(section, "hook_lug_y_offset_ratio_left", fallback=None),
  68. hook_lug_x_offset_ratio_right=cfg.getfloat(section, "hook_lug_x_offset_ratio_right", fallback=None),
  69. hook_lug_y_offset_ratio_right=cfg.getfloat(section, "hook_lug_y_offset_ratio_right", fallback=None),
  70. )
  71. left_rtsp = cfg.get(section, "left_rtsp")
  72. right_rtsp = cfg.get(section, "right_rtsp")
  73. left_topic = cfg.get(section, "left_topic", fallback="")
  74. right_topic = cfg.get(section, "right_topic", fallback="")
  75. cameras = []
  76. if left_rtsp:
  77. cameras.append(CameraModel(position=CameraPosition.LEFT, rtsp_url=left_rtsp, topic=left_topic))
  78. if right_rtsp:
  79. cameras.append(CameraModel(position=CameraPosition.RIGHT, rtsp_url=right_rtsp, topic=right_topic))
  80. bucket.cameras = cameras
  81. config.buckets.append(bucket)
  82. _ensure_auto_calib_defaults(cfg, config_path)
  83. # AutoRestart
  84. if cfg.has_section("AutoRestart"):
  85. ar = config.auto_restart
  86. ar.enabled = cfg.getboolean("AutoRestart", "enabled", fallback=False)
  87. ar.interval = RestartInterval(cfg.get("AutoRestart", "interval", fallback="day"))
  88. ar.hour = cfg.getint("AutoRestart", "hour", fallback=3)
  89. ar.minute = cfg.getint("AutoRestart", "minute", fallback=0)
  90. ar.target = RestartTarget(cfg.get("AutoRestart", "target", fallback="app"))
  91. ar.weekdays = cfg.getint("AutoRestart", "weekdays", fallback=0)
  92. ar.day_of_month = cfg.getint("AutoRestart", "day_of_month", fallback=1)
  93. ar.countdown = cfg.getint("AutoRestart", "countdown", fallback=60)
  94. return config
  95. _AUTO_CALIB_DEFAULTS = {
  96. "auto_calib_ready_frames": "3",
  97. "auto_calib_duration_secs": "1.0",
  98. "auto_calib_min_samples": "2",
  99. }
  100. def _ensure_auto_calib_defaults(cfg, config_path: str):
  101. """配置文件缺少自动标定参数时自动补写默认值(仅在文件存在且发生变更时写回)。"""
  102. import os
  103. if not os.path.exists(config_path):
  104. return
  105. if not cfg.has_section("AI"):
  106. cfg.add_section("AI")
  107. changed = False
  108. for key, val in _AUTO_CALIB_DEFAULTS.items():
  109. if not cfg.has_option("AI", key):
  110. cfg.set("AI", key, val)
  111. changed = True
  112. if changed:
  113. with open(config_path, "w", encoding="utf-8") as f:
  114. cfg.write(f)