V1.0.0.7 - 2025/12/22
* Database improved all
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using LFP_Manager.DataStructure;
|
||||
using DevExpress.Utils.Drawing;
|
||||
using LFP_Manager.DataStructure;
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Data.SQLite;
|
||||
@@ -17,9 +18,9 @@ namespace LFP_Manager.Utils
|
||||
public static string DbSchemaTableFileName = @"\sql\DB_SCHEMA_TABLE.sql";
|
||||
public static string ModuleTableName = @"TModule";
|
||||
|
||||
public static string LogDbFilePath = @"\db";
|
||||
public static string LogDbFileNameFormat = @"\{0}\{1}_{2}_LOG.DB";
|
||||
public static string LogDbSchemaTableFileName = @"\sql\LOG_DB_SCHEMA_TABLE.sql";
|
||||
public static string LogDbFilePath = @"db";
|
||||
public static string LogDbFileNameFormat = @"{0}\{1}_{2}_LOG.DB";
|
||||
public static string LogDbSchemaTableFileName = @"sql\LOG_DB_SCHEMA_TABLE.sql";
|
||||
|
||||
public static DateTime Delay(int ms)
|
||||
{
|
||||
@@ -29,8 +30,7 @@ namespace LFP_Manager.Utils
|
||||
|
||||
while (afterMoment >= thisMoment)
|
||||
{
|
||||
System.Windows.Forms.Application.DoEvents();
|
||||
|
||||
Application.DoEvents();
|
||||
thisMoment = DateTime.Now;
|
||||
}
|
||||
|
||||
@@ -53,6 +53,21 @@ namespace LFP_Manager.Utils
|
||||
command.Dispose();
|
||||
}
|
||||
|
||||
#region COMMON DB HELPERS
|
||||
private static DataTable ExecSelect(string dbPath, string sql)
|
||||
{
|
||||
var dt = new DataTable();
|
||||
using (var conn = new SQLiteConnection(@"Data Source=" + dbPath))
|
||||
using (var adp = new SQLiteDataAdapter(sql, conn))
|
||||
{
|
||||
conn.Open();
|
||||
adp.AcceptChangesDuringFill = false;
|
||||
adp.Fill(dt);
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region CREATE DATABASE
|
||||
|
||||
public static void DbCreate(string mSN, string bName)
|
||||
@@ -163,57 +178,41 @@ namespace LFP_Manager.Utils
|
||||
return;
|
||||
}
|
||||
|
||||
public static void LogDbCreateNew(string aModel)
|
||||
#endregion
|
||||
|
||||
#region DB CREATE FUNCTION (LOG)
|
||||
public static void DbCreateLOG(CommConfig aConfig)
|
||||
{
|
||||
string result = "";
|
||||
string ModelName = aModel;
|
||||
//public static string LogDbFileNameFormat = @"\{0}\{1}_{2}_LOG.DB";
|
||||
string dbFilename = String.Format(LogDbFileNameFormat
|
||||
, String.Format("{0:yyMM}", DateTime.Now)
|
||||
, String.Format("{0:yyMMdd}", DateTime.Now)
|
||||
, ModelName
|
||||
);
|
||||
string dbFilePath = Path.GetDirectoryName(Application.ExecutablePath) + LogDbFilePath + dbFilename;
|
||||
string modelName = csConstData.UART_MODEL[aConfig.UartModelIndex];
|
||||
|
||||
if (Directory.Exists(System.IO.Path.GetDirectoryName(dbFilePath)) == false)
|
||||
Directory.CreateDirectory(System.IO.Path.GetDirectoryName(dbFilePath));
|
||||
string folder = string.Format("{0:yyMM}", DateTime.Now);
|
||||
string file = string.Format("{0}_{1}_LOG.DB", string.Format("{0:yyMMdd}", DateTime.Now), modelName);
|
||||
string exeDir = Path.GetDirectoryName(Application.ExecutablePath);
|
||||
string dbFilePath = csUtils.CombineApp(exeDir, LogDbFilePath, folder, file);
|
||||
|
||||
string dir = Path.GetDirectoryName(dbFilePath);
|
||||
if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
|
||||
|
||||
if (File.Exists(dbFilePath)) return;
|
||||
|
||||
// Create database
|
||||
SQLiteConnection.CreateFile(dbFilePath);
|
||||
|
||||
// Open database
|
||||
string strConn = @"Data Source=" + dbFilePath;
|
||||
using (var connection = new SQLiteConnection(strConn))
|
||||
string schemaFile = csUtils.CombineApp(LogDbSchemaTableFileName);
|
||||
string query = File.ReadAllText(schemaFile);
|
||||
|
||||
using (var connection = new SQLiteConnection(@"Data Source=" + dbFilePath))
|
||||
{
|
||||
connection.Open();
|
||||
try
|
||||
using (var command = connection.CreateCommand())
|
||||
{
|
||||
// Create table
|
||||
using (SQLiteCommand command = connection.CreateCommand())
|
||||
{
|
||||
string schemaFile = Path.GetDirectoryName(Application.ExecutablePath) + LogDbSchemaTableFileName;
|
||||
string query = File.ReadAllText(schemaFile);
|
||||
|
||||
command.CommandText = query;
|
||||
SQLiteDataReader reader = null;
|
||||
reader = command.ExecuteReader();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
result = e.Message;
|
||||
}
|
||||
finally
|
||||
{
|
||||
connection.Close();
|
||||
if (result != "") throw new Exception(result);
|
||||
command.CommandText = query;
|
||||
using (var reader = command.ExecuteReader()) { /* schema create */ }
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region MAKE LOT NUMBER
|
||||
public static string MakeLotNumber(string mSN)
|
||||
{
|
||||
@@ -474,126 +473,195 @@ namespace LFP_Manager.Utils
|
||||
|
||||
#region BMS DATA INSERT AND UPDATE
|
||||
|
||||
public static void BmsLogDataInsert(string ModelName, ref CsDeviceData.DeviceModuleData mData, DateTime dateTime, int cvUnit)
|
||||
public static string GetDbFilePath(string modelName, DateTime dateTime)
|
||||
{
|
||||
string folder = string.Format("{0:yyMM}", dateTime); // 2512
|
||||
string file = string.Format("{0}_{1}_LOG.DB", string.Format("{0:yyMMdd}", dateTime), modelName); // 251221_LFPM-48100SB_LOG.DB
|
||||
string exeDir = Path.GetDirectoryName(Application.ExecutablePath);
|
||||
string dbPath = csUtils.CombineApp(exeDir, LogDbFilePath, folder, file); // db\2512\251221_LFPM-48100SB_LOG.DB
|
||||
return dbPath;
|
||||
}
|
||||
|
||||
public static void BmsLogDataInsert(string ModelName, ref CsDeviceData.DeviceModuleData mData, DateTime dateTime, int cvUnit, int log_type = 0)
|
||||
{
|
||||
string result = "";
|
||||
//string ModelName = csConstData.CAN_MODEL[aConfig.CanModelIndex];
|
||||
//public static string LogDbFileNameFormat = @"\{0}\{1}_{2}_LOG.DB";
|
||||
string dbFilename = String.Format(LogDbFileNameFormat
|
||||
, String.Format("{0:yyMM}", DateTime.Now)
|
||||
, String.Format("{0:yyMMdd}", DateTime.Now)
|
||||
, ModelName
|
||||
);
|
||||
string dbFilePath = Path.GetDirectoryName(Application.ExecutablePath) + LogDbFilePath + dbFilename;
|
||||
string dbFilePath = GetDbFilePath(ModelName, dateTime);
|
||||
|
||||
if (Directory.Exists(Path.GetDirectoryName(dbFilePath)) == false)
|
||||
throw new Exception("No Log DB file path");
|
||||
if (File.Exists(dbFilePath) == false)
|
||||
throw new Exception(String.Format("No Log DB file - BmsLogDataInsert ({0})", dbFilename));
|
||||
throw new Exception(String.Format("No Log DB file - BmsLogDataInsert ({0})", dbFilePath));
|
||||
|
||||
// Open database
|
||||
string strConn = @"Data Source=" + dbFilePath;
|
||||
using (var connection = new SQLiteConnection(strConn))
|
||||
{
|
||||
SQLiteTransaction tran = null;
|
||||
|
||||
try
|
||||
{
|
||||
connection.Open();
|
||||
BeginTran(connection);
|
||||
|
||||
// 기존 BeginTran/CommitTran을 유지하고 싶으면 tran 대신 그걸 쓰셔도 됩니다.
|
||||
// 다만 C# 7.3에서는 아래 표준 방식이 제일 안전합니다.
|
||||
tran = connection.BeginTransaction();
|
||||
|
||||
// Insert data
|
||||
using (SQLiteCommand command = connection.CreateCommand())
|
||||
{
|
||||
command.Transaction = tran;
|
||||
|
||||
// 스키마 기준: cell 15, temp 4 고정
|
||||
const int CELL_MAX = 15;
|
||||
const int TEMP_MAX = 4;
|
||||
|
||||
//sSQL = "insert into TrendTable ( TrendStamp, TagName, TagValue) Values ( " + IntToStr(stamp) + "," + name + "," + value + ");";
|
||||
command.CommandText = String.Format("INSERT INTO TModuleValue (");
|
||||
command.CommandText += "create_date" // 0
|
||||
+ ", module_no" // 1
|
||||
+ ", model_name" // 2
|
||||
+ ", module_sn" // 3
|
||||
+ ", fw_ver" // 4
|
||||
+ ", comm_fail" // 5
|
||||
+ ", op_status" // 6
|
||||
+ ", alarm_status" // 7
|
||||
+ ", warning" // 8
|
||||
+ ", fault" // 9
|
||||
+ ", module_voltage" // 10
|
||||
+ ", module_current" // 11
|
||||
+ ", module_soc" // 12
|
||||
+ ", module_soh" // 13
|
||||
+ ", module_cyclecount" // 14
|
||||
;
|
||||
for (int i = 0; i < mData.cellQty; i++)
|
||||
{
|
||||
command.CommandText += String.Format(", cell_voltage_{0:00}", i + 1); // 14 ~ 28; 15 cells
|
||||
}
|
||||
for (int i = 0; i < mData.tempQty; i++)
|
||||
{
|
||||
command.CommandText += String.Format(", temperature_{0:00}", i + 1); // 29 ~ 32; 6 temps
|
||||
}
|
||||
command.CommandText = "INSERT INTO TModuleValue ("
|
||||
+ "create_date"
|
||||
+ ", log_type"
|
||||
+ ", module_no"
|
||||
+ ", model_name"
|
||||
+ ", module_sn"
|
||||
+ ", fw_ver"
|
||||
+ ", comm_fail"
|
||||
+ ", op_status"
|
||||
+ ", alarm_status"
|
||||
+ ", warning"
|
||||
+ ", fault"
|
||||
+ ", module_voltage"
|
||||
+ ", module_current"
|
||||
+ ", module_soc"
|
||||
+ ", module_soh"
|
||||
+ ", module_cyclecount"
|
||||
+ ", cv_diff";
|
||||
|
||||
for (int i = 0; i < CELL_MAX; i++)
|
||||
command.CommandText += $", cell_voltage_{i + 1:00}";
|
||||
|
||||
command.CommandText += ", tp_diff";
|
||||
|
||||
for (int i = 0; i < TEMP_MAX; i++)
|
||||
command.CommandText += $", temperature_{i + 1:00}";
|
||||
|
||||
command.CommandText += ""
|
||||
+ ", ext1_temp" // 35
|
||||
+ ", ext2_temp" // 35
|
||||
+ ", chg_option" // 35
|
||||
+ ")"
|
||||
+ " Values (";
|
||||
+ ", ext1_temp"
|
||||
+ ", ext2_temp"
|
||||
+ ", chg_option"
|
||||
+ ") VALUES (";
|
||||
|
||||
int total = 15 + mData.cellQty + mData.tempQty + 3;
|
||||
int total = 16 + 1 + CELL_MAX + 1 + TEMP_MAX + 3;
|
||||
// 16(기본 0~15) + cv_diff(1) + cell15 + tp_diff(1) + temp4 + ext1/ext2/chg(3)
|
||||
|
||||
for (int i = 0; i < (total - 1); i++) command.CommandText += "?,";
|
||||
for (int i = 0; i < total - 1; i++) command.CommandText += "?,";
|
||||
command.CommandText += "?);";
|
||||
|
||||
SQLiteParameter[] p = new SQLiteParameter[total];
|
||||
|
||||
for (int i = 0; i < total; i++)
|
||||
{
|
||||
if (i == 0)
|
||||
p[i] = new SQLiteParameter(DbType.DateTime);
|
||||
else
|
||||
p[i] = new SQLiteParameter();
|
||||
command.Parameters.Add(p[i]);
|
||||
}
|
||||
command.Parameters.Add(new SQLiteParameter());
|
||||
|
||||
int j = 0;
|
||||
p[j++].Value = dateTime; // 0 create_date
|
||||
p[j++].Value = mData.mNo; // 1 Module No
|
||||
p[j++].Value = mData.Information.ModelName; // 2 model_name
|
||||
p[j++].Value = mData.Information.HwSerialNumber; // 3 module_sn
|
||||
p[j++].Value = mData.Information.SwProductRev; // 4 fw_ver
|
||||
|
||||
p[j++].Value = mData.ShelfCommFail; // 5 comm_fail
|
||||
p[j++].Value = mData.StatusData.status; // 6 op_status
|
||||
p[j++].Value = mData.StatusData.batteryStatus; // 7 alarm_status
|
||||
p[j++].Value = mData.StatusData.warning; // 8 warning
|
||||
p[j++].Value = mData.StatusData.protect; // 9 fault
|
||||
p[j++].Value = ((float)mData.ValueData.voltage / 10).ToString(); // 10 module_voltage
|
||||
p[j++].Value = ((float)mData.ValueData.current / 10).ToString(); // 11 module_current
|
||||
p[j++].Value = ((float)mData.ValueData.SOC / 10).ToString(); // 12 module_soc
|
||||
p[j++].Value = ((float)mData.ValueData.SOH / 10).ToString(); // 13 module_soh
|
||||
p[j++].Value = ((float)mData.ValueData.cycleCount / 1).ToString(); // 14 module_soh
|
||||
command.Parameters[j++].Value = dateTime; // create_date
|
||||
command.Parameters[j++].Value = log_type; // log_type
|
||||
command.Parameters[j++].Value = mData.mNo; // module_no
|
||||
command.Parameters[j++].Value = (object)mData.Information.ModelName ?? DBNull.Value;
|
||||
command.Parameters[j++].Value = (object)mData.Information.HwSerialNumber ?? DBNull.Value;
|
||||
command.Parameters[j++].Value = (object)mData.Information.SwProductRev ?? DBNull.Value;
|
||||
|
||||
for (int i = 0; i < mData.cellQty; i++)
|
||||
command.Parameters[j++].Value = mData.ShelfCommFail; // comm_fail (bool -> 0/1도 가능)
|
||||
command.Parameters[j++].Value = mData.StatusData.status; // op_status
|
||||
command.Parameters[j++].Value = mData.StatusData.batteryStatus; // alarm_status
|
||||
command.Parameters[j++].Value = mData.StatusData.warning; // warning
|
||||
command.Parameters[j++].Value = mData.StatusData.protect; // fault
|
||||
|
||||
command.Parameters[j++].Value = mData.ValueData.voltage / 10.0; // module_voltage
|
||||
command.Parameters[j++].Value = mData.ValueData.current / 10.0; // module_current
|
||||
command.Parameters[j++].Value = mData.ValueData.SOC / 10.0; // module_soc
|
||||
command.Parameters[j++].Value = mData.ValueData.SOH / 10.0; // module_soh
|
||||
command.Parameters[j++].Value = mData.ValueData.cycleCount; // module_cyclecount
|
||||
|
||||
// cv_diff = 셀 전압 max-min (V)
|
||||
object cvDiffValue = DBNull.Value;
|
||||
if (mData.ValueData.CellVoltage != null && mData.cellQty > 0)
|
||||
{
|
||||
p[j++].Value = ((float)mData.ValueData.CellVoltage[i] / cvUnit).ToString(); // 15 cell_voltage_01
|
||||
}
|
||||
for (int i = 0; i < mData.tempQty; i++)
|
||||
{
|
||||
p[j++].Value = ((float)mData.ValueData.CellTemperature[i] / 10).ToString(); // 30 temperature_01
|
||||
}
|
||||
p[j++].Value = ((float)mData.ValueData.MosTemperature / 10).ToString(); // 34 temperature_ext1 - FET Temp
|
||||
p[j++].Value = ((float)mData.ValueData.AmbTemperature / 10).ToString(); // 35 temperature_ext2 - Lmt Temp
|
||||
int n = Math.Min(mData.cellQty, CELL_MAX);
|
||||
double minV = double.MaxValue;
|
||||
double maxV = double.MinValue;
|
||||
|
||||
p[j++].Value = mData.CalibrationData.Current.ChargeOption.ToString(); // 36 chg_option
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
double v = mData.ValueData.CellVoltage[i] / (double)cvUnit;
|
||||
if (v < minV) minV = v;
|
||||
if (v > maxV) maxV = v;
|
||||
}
|
||||
|
||||
if (minV != double.MaxValue)
|
||||
cvDiffValue = (maxV - minV);
|
||||
}
|
||||
command.Parameters[j++].Value = cvDiffValue; // cv_diff
|
||||
|
||||
// cell_voltage_01..15 (없으면 NULL)
|
||||
for (int i = 0; i < CELL_MAX; i++)
|
||||
{
|
||||
if (mData.ValueData.CellVoltage != null && i < mData.cellQty)
|
||||
command.Parameters[j++].Value = mData.ValueData.CellVoltage[i] / (double)cvUnit;
|
||||
else
|
||||
command.Parameters[j++].Value = DBNull.Value;
|
||||
}
|
||||
|
||||
// tp_diff = 온도 max-min (°C)
|
||||
object tpDiffValue = DBNull.Value;
|
||||
if (mData.ValueData.CellTemperature != null && mData.tempQty > 0)
|
||||
{
|
||||
int n = Math.Min(mData.tempQty, TEMP_MAX);
|
||||
double minT = double.MaxValue;
|
||||
double maxT = double.MinValue;
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
double t = mData.ValueData.CellTemperature[i] / 10.0;
|
||||
if (t < minT) minT = t;
|
||||
if (t > maxT) maxT = t;
|
||||
}
|
||||
|
||||
if (minT != double.MaxValue)
|
||||
tpDiffValue = (maxT - minT);
|
||||
}
|
||||
command.Parameters[j++].Value = tpDiffValue; // tp_diff
|
||||
|
||||
// temperature_01..04 (없으면 NULL)
|
||||
for (int i = 0; i < TEMP_MAX; i++)
|
||||
{
|
||||
if (mData.ValueData.CellTemperature != null && i < mData.tempQty)
|
||||
command.Parameters[j++].Value = mData.ValueData.CellTemperature[i] / 10.0;
|
||||
else
|
||||
command.Parameters[j++].Value = DBNull.Value;
|
||||
}
|
||||
|
||||
command.Parameters[j++].Value = mData.ValueData.MosTemperature / 10.0; // ext1_temp
|
||||
command.Parameters[j++].Value = mData.ValueData.AmbTemperature / 10.0; // ext2_temp
|
||||
command.Parameters[j++].Value = (short)mData.CalibrationData.Current.ChargeOption; // chg_option
|
||||
|
||||
if (j != total)
|
||||
throw new Exception(string.Format("Parameter mismatch: j={0}, total={1}", j, total));
|
||||
|
||||
command.ExecuteNonQuery();
|
||||
|
||||
CommitTran(connection);
|
||||
}
|
||||
tran.Commit();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (tran != null) tran.Rollback();
|
||||
}
|
||||
catch { /* rollback 실패는 무시 or 로그 */ }
|
||||
|
||||
result = e.Message;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (tran != null) tran.Dispose();
|
||||
|
||||
if (connection.State == ConnectionState.Open)
|
||||
connection.Close();
|
||||
if (result != "") throw new Exception(result);
|
||||
@@ -1010,7 +1078,26 @@ namespace LFP_Manager.Utils
|
||||
#endregion
|
||||
|
||||
#region ALARM HISTROTY DB FUNCTION
|
||||
public static DataTable GetBmsAlarmDataByDataTable(string modelName, DateTime aDateTime, string qry)
|
||||
public static DataTable GetBmsAlarmDataByDataTable(CommConfig aConfig, DateTime aDateTime, string qry)
|
||||
{
|
||||
string modelName = csConstData.UART_MODEL[aConfig.UartModelIndex]; // LFPM-48100SB
|
||||
string folder = string.Format("{0:yyMM}", aDateTime); // 2512
|
||||
string file = string.Format("{0}_{1}_LOG.DB", string.Format("{0:yyMMdd}", aDateTime), modelName); // 251221_LFPM-48100SB_LOG.DB
|
||||
string exeDir = Path.GetDirectoryName(Application.ExecutablePath);
|
||||
string dbPath = csUtils.CombineApp(exeDir, LogDbFilePath, folder, file); // db\2512\251221_LFPM-48100SB_LOG.DB
|
||||
|
||||
if (!File.Exists(dbPath)) return null;
|
||||
|
||||
string sql = string.IsNullOrWhiteSpace(qry)
|
||||
? "SELECT * FROM TAlarmHistory ORDER BY create_date DESC"
|
||||
: "SELECT * FROM TAlarmHistory " + qry;
|
||||
|
||||
var dt = ExecSelect(dbPath, sql);
|
||||
dt.TableName = "TAlarmHistory";
|
||||
return dt;
|
||||
}
|
||||
|
||||
public static DataTable GetBmsAlarmDataByDataTable1(string modelName, DateTime aDateTime, string qry)
|
||||
{
|
||||
// 결과 테이블(항상 non-null 반환)
|
||||
var dtResult = new DataTable("TAlarmHistory");
|
||||
@@ -1020,7 +1107,7 @@ namespace LFP_Manager.Utils
|
||||
LogDbFileNameFormat,
|
||||
aDateTime.ToString("yyMM"),
|
||||
aDateTime.ToString("yyMMdd"),
|
||||
modelName);
|
||||
modelName); // \2512\{1}_{2}_LOG.DB";
|
||||
|
||||
// 실행파일 경로 + 로그 DB 상대경로 + 파일명 안전 결합
|
||||
string exeDir = Path.GetDirectoryName(Application.ExecutablePath);
|
||||
@@ -1316,13 +1403,9 @@ namespace LFP_Manager.Utils
|
||||
{
|
||||
string result = "";
|
||||
DataTable dtResult = null;
|
||||
|
||||
string ModelName = csConstData.UART_MODEL[aConfig.UartModelIndex];
|
||||
string dbFilename = String.Format(LogDbFileNameFormat
|
||||
, String.Format("{0:yyMM}", aDate)
|
||||
, String.Format("{0:yyMMdd}", aDate)
|
||||
, ModelName
|
||||
);
|
||||
string dbFilePath = Path.GetDirectoryName(Application.ExecutablePath) + LogDbFilePath + dbFilename;
|
||||
string dbFilePath = GetDbFilePath(ModelName, aDate);
|
||||
|
||||
if (Directory.Exists(System.IO.Path.GetDirectoryName(dbFilePath)) == false)
|
||||
return dtResult;
|
||||
|
||||
Reference in New Issue
Block a user