db_models.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import sqlite3
  2. import json
  3. import logging
  4. from pathlib import Path
  5. logger = logging.getLogger(__name__)
  6. # 数据库文件默认名(与 rtsp_config.yaml 同级)
  7. DEFAULT_DB_NAME = "pickup_config.db"
  8. def get_db_path(config_dir=None):
  9. # 默认放在 config/ 目录下
  10. if config_dir is None:
  11. config_dir = Path(__file__).parent
  12. return Path(config_dir) / DEFAULT_DB_NAME
  13. def get_connection(db_path=None):
  14. # 获取 SQLite 连接,启用 WAL 模式以支持并发读写
  15. if db_path is None:
  16. db_path = get_db_path()
  17. conn = sqlite3.connect(str(db_path), timeout=10)
  18. conn.row_factory = sqlite3.Row
  19. # WAL 模式:允许读写并发,避免锁阻塞
  20. conn.execute("PRAGMA journal_mode=WAL")
  21. # 启用外键约束
  22. conn.execute("PRAGMA foreign_keys=ON")
  23. return conn
  24. def init_db(db_path=None):
  25. # 初始化数据库表结构(幂等操作,已有表则跳过)
  26. conn = get_connection(db_path)
  27. try:
  28. conn.executescript(SCHEMA_SQL)
  29. conn.commit()
  30. logger.info(f"数据库初始化完成: {db_path or get_db_path()}")
  31. finally:
  32. conn.close()
  33. # 完整的表结构定义
  34. SCHEMA_SQL = """
  35. -- 水厂表:每个水厂一条记录
  36. CREATE TABLE IF NOT EXISTS plant (
  37. id INTEGER PRIMARY KEY AUTOINCREMENT,
  38. name TEXT NOT NULL UNIQUE, -- 水厂名称(如"锡山中荷")
  39. enabled INTEGER NOT NULL DEFAULT 0, -- 是否启用(0=禁用, 1=启用)
  40. project_id INTEGER NOT NULL, -- 项目ID(用于数据上报)
  41. push_url TEXT NOT NULL DEFAULT '', -- 异常推送接口URL
  42. created_at TEXT DEFAULT (datetime('now','localtime')),
  43. updated_at TEXT DEFAULT (datetime('now','localtime'))
  44. );
  45. -- RTSP 流表:每个拾音器/摄像头一条记录
  46. CREATE TABLE IF NOT EXISTS rtsp_stream (
  47. id INTEGER PRIMARY KEY AUTOINCREMENT,
  48. plant_id INTEGER NOT NULL, -- 所属水厂
  49. name TEXT NOT NULL DEFAULT '', -- 摄像头/拾音器名称(用于告警显示)
  50. url TEXT NOT NULL, -- RTSP 流地址
  51. channel INTEGER NOT NULL, -- 通道号
  52. device_code TEXT NOT NULL, -- 设备编码(唯一标识,用于文件命名)
  53. pump_name TEXT NOT NULL DEFAULT '', -- 关联泵名称(用于流量/状态查询)
  54. model_subdir TEXT DEFAULT '', -- 模型子目录(默认使用 device_code)
  55. enabled INTEGER NOT NULL DEFAULT 1, -- 是否启用该流
  56. created_at TEXT DEFAULT (datetime('now','localtime')),
  57. updated_at TEXT DEFAULT (datetime('now','localtime')),
  58. FOREIGN KEY (plant_id) REFERENCES plant(id) ON DELETE CASCADE,
  59. UNIQUE(device_code) -- device_code 全局唯一
  60. );
  61. -- 流量 PLC 映射表:泵名 -> PLC 地址
  62. CREATE TABLE IF NOT EXISTS flow_plc (
  63. id INTEGER PRIMARY KEY AUTOINCREMENT,
  64. plant_id INTEGER NOT NULL,
  65. pump_name TEXT NOT NULL, -- 泵名称/标识(如"A", "高压泵1流量")
  66. plc_address TEXT NOT NULL, -- PLC 数据点位地址
  67. FOREIGN KEY (plant_id) REFERENCES plant(id) ON DELETE CASCADE,
  68. UNIQUE(plant_id, pump_name)
  69. );
  70. -- 泵状态 PLC 点位表:用于检测泵启停
  71. CREATE TABLE IF NOT EXISTS pump_status_plc (
  72. id INTEGER PRIMARY KEY AUTOINCREMENT,
  73. plant_id INTEGER NOT NULL,
  74. pump_name TEXT NOT NULL, -- 拾音器关联的泵名称(对应 rtsp_stream.pump_name)
  75. point TEXT NOT NULL, -- PLC 运行状态点位地址
  76. point_name TEXT NOT NULL DEFAULT '', -- 点位显示名称(如"1#RO高压泵")
  77. FOREIGN KEY (plant_id) REFERENCES plant(id) ON DELETE CASCADE
  78. );
  79. -- 系统级配置表:KV 存储,存放 audio/prediction/push_notification/scada_api/human_detection
  80. -- 通过 section + key 组合定位配置项
  81. CREATE TABLE IF NOT EXISTS system_config (
  82. id INTEGER PRIMARY KEY AUTOINCREMENT,
  83. section TEXT NOT NULL, -- 配置区域(如 audio, prediction, push_notification)
  84. key TEXT NOT NULL, -- 配置键(支持点号嵌套,如 voting.window_size)
  85. value TEXT NOT NULL DEFAULT '', -- 配置值(JSON 序列化存储)
  86. value_type TEXT NOT NULL DEFAULT 'str', -- 值类型标识(str/int/float/bool/json)
  87. description TEXT DEFAULT '', -- 配置项说明
  88. updated_at TEXT DEFAULT (datetime('now','localtime')),
  89. UNIQUE(section, key)
  90. );
  91. -- 更新时间触发器:plant 表
  92. CREATE TRIGGER IF NOT EXISTS plant_updated_at
  93. AFTER UPDATE ON plant
  94. BEGIN
  95. UPDATE plant SET updated_at = datetime('now','localtime') WHERE id = NEW.id;
  96. END;
  97. -- 更新时间触发器:rtsp_stream 表
  98. CREATE TRIGGER IF NOT EXISTS stream_updated_at
  99. AFTER UPDATE ON rtsp_stream
  100. BEGIN
  101. UPDATE rtsp_stream SET updated_at = datetime('now','localtime') WHERE id = NEW.id;
  102. END;
  103. -- 更新时间触发器:system_config 表
  104. CREATE TRIGGER IF NOT EXISTS config_updated_at
  105. AFTER UPDATE ON system_config
  106. BEGIN
  107. UPDATE system_config SET updated_at = datetime('now','localtime') WHERE id = NEW.id;
  108. END;
  109. """