feat(config): 添加配置管理和MQTT模拟服务功能
- 实现了应用配置的数据类结构(MqttConfig, TmsConfig, AppConfig) - 创建了配置加载和解析功能,支持从YAML文件读取配置 - 添加了TDengine数据库配置和连接池管理 - 实现了MQTT客户端依赖注入和服务构建 - 创建了钻孔实时数据的ORM映射和SQL构建功能 - 实现了TDengine Writer用于数据写入超级表 - 添加了MQTT模拟服务,支持发布、订阅和数据转发功能 - 创建了随机数据发送器用于测试 - 实现了消息持久化到本地文件功能 - 配置了数据库连接池和SQL执行功能
This commit is contained in:
122
db/orm.py
Normal file
122
db/orm.py
Normal file
@@ -0,0 +1,122 @@
|
||||
import re
|
||||
import time
|
||||
|
||||
|
||||
DB_COLUMNS = [
|
||||
"ts",
|
||||
"stknum",
|
||||
"recid",
|
||||
"seqid",
|
||||
"actual_date",
|
||||
"actual_time",
|
||||
"actcod",
|
||||
"deptbitm",
|
||||
"deptbitv",
|
||||
"deptmeas",
|
||||
"deptvert",
|
||||
"blkpos",
|
||||
"ropa",
|
||||
"hkla",
|
||||
"hklx",
|
||||
"woba",
|
||||
"wobx",
|
||||
"torqa",
|
||||
"torqx",
|
||||
"rpma",
|
||||
"sppa",
|
||||
"chkp",
|
||||
"spm1",
|
||||
"spm2",
|
||||
"spm3",
|
||||
"tvolact",
|
||||
"tvolcact",
|
||||
"mfop",
|
||||
"mfoa",
|
||||
"mfia",
|
||||
"mdoa",
|
||||
"mdia",
|
||||
"mtoa",
|
||||
"mtia",
|
||||
"mcoa",
|
||||
"mcia",
|
||||
"stkc",
|
||||
"lagstks",
|
||||
"deptretm",
|
||||
"gasa",
|
||||
"space1",
|
||||
"space2",
|
||||
"space3",
|
||||
"space4",
|
||||
"space5",
|
||||
]
|
||||
|
||||
|
||||
INT_COLUMNS = {"stknum", "recid", "seqid", "actcod", "rpma", "spm1", "spm2", "spm3", "mfop", "stkc", "lagstks"}
|
||||
|
||||
|
||||
def sanitize_identifier(value, fallback):
|
||||
cleaned = re.sub(r"[^A-Za-z0-9_]", "_", str(value or ""))
|
||||
if not cleaned:
|
||||
cleaned = fallback
|
||||
if cleaned[0].isdigit():
|
||||
cleaned = f"t_{cleaned}"
|
||||
return cleaned.lower()
|
||||
|
||||
|
||||
def sql_quote(value):
|
||||
return "'" + str(value).replace("'", "''") + "'"
|
||||
|
||||
|
||||
def to_int(value, default=0):
|
||||
try:
|
||||
return int(value)
|
||||
except Exception:
|
||||
return default
|
||||
|
||||
|
||||
def to_float(value, default=0.0):
|
||||
try:
|
||||
return float(value)
|
||||
except Exception:
|
||||
return default
|
||||
|
||||
|
||||
class DrillingRealtimeORM:
|
||||
def __init__(self, database, stable="drilling_realtime_st", default_device_code="GJ-304-0088"):
|
||||
self.database = database
|
||||
self.stable = stable
|
||||
self.default_device_code = default_device_code or "GJ-304-0088"
|
||||
|
||||
def build_insert_sql(self, payload):
|
||||
if not isinstance(payload, dict):
|
||||
raise ValueError("payload is not JSON object")
|
||||
meta = payload.get("meta") if isinstance(payload.get("meta"), dict) else {}
|
||||
data = payload.get("data") if isinstance(payload.get("data"), dict) else {}
|
||||
|
||||
equipment_code = (
|
||||
str(self.default_device_code).strip()
|
||||
or str(meta.get("equipment_code", "")).strip()
|
||||
or str(meta.get("equipment_sn", "")).strip()
|
||||
or "GJ-304-0088"
|
||||
)
|
||||
table_name = sanitize_identifier(
|
||||
f"drilling_realtime_{equipment_code}",
|
||||
"drilling_realtime_default",
|
||||
)
|
||||
|
||||
values = []
|
||||
for col in DB_COLUMNS:
|
||||
if col == "ts":
|
||||
raw = data.get("ts", data.get("record_time", int(time.time() * 1000)))
|
||||
values.append(str(to_int(raw, int(time.time() * 1000))))
|
||||
elif col in INT_COLUMNS:
|
||||
values.append(str(to_int(data.get(col, 0), 0)))
|
||||
else:
|
||||
values.append(str(to_float(data.get(col, 0), 0.0)))
|
||||
|
||||
columns_sql = ", ".join([f"`{column}`" for column in DB_COLUMNS])
|
||||
values_sql = ", ".join(values)
|
||||
return (
|
||||
f"INSERT INTO `{self.database}`.`{table_name}` USING `{self.database}`.`{self.stable}` "
|
||||
f"TAGS ({sql_quote(equipment_code)}) ({columns_sql}) VALUES ({values_sql})"
|
||||
)
|
||||
Reference in New Issue
Block a user