SmartFactory_NEOL/SOURCE/NILM_Manager_D104/uMain.pas
2026-09-04 14:06:10 +09:00

1244 lines
45 KiB
ObjectPascal

unit uMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, uMQTTComps, StdCtrls, Grids, BaseGrid, AdvGrid, uMQTT ,
ExtCtrls, DateUtils, ComCtrls, Menus, ScktComp, inifiles,
Buttons, ZConnection, MQTT,
ZAbstractDataset, ZDataset, DB, ZAbstractRODataset, ZAbstractConnection,
System.JSON, FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Error,
FireDAC.UI.Intf, FireDAC.Phys.Intf, FireDAC.Stan.Def, FireDAC.Stan.Pool,
FireDAC.Stan.Async, FireDAC.Phys, FireDAC.Stan.Param, FireDAC.DatS,
FireDAC.DApt.Intf, FireDAC.DApt, FireDAC.Phys.PGDef, FireDAC.VCLUI.Wait,
FireDAC.Comp.UI, FireDAC.Phys.PG, FireDAC.Comp.DataSet, FireDAC.Comp.Client,
System.Generics.Collections, System.StrUtils, cxGraphics, cxControls,
cxLookAndFeels, cxLookAndFeelPainters, cxStyles, cxCustomData, cxFilter,
cxData, cxDataStorage, cxEdit, cxNavigator, dxDateRanges,
dxScrollbarAnnotations, cxGridLevel, cxGridCustomTableView, cxGridTableView,
cxClasses, cxGridCustomView, cxGrid;
type
TfrmMain = class(TForm)
MQTTClient1: TMQTTClient;
initTimer: TTimer;
StatusBar1: TStatusBar;
MainMenu1: TMainMenu;
File1: TMenuItem;
Config1: TMenuItem;
N2: TMenuItem;
Connect1: TMenuItem;
Disconnect1: TMenuItem;
insertTimer: TTimer;
File2: TMenuItem;
DebugMode1: TMenuItem;
N8: TMenuItem;
ProgramExit1: TMenuItem;
ZConnection1: TZConnection;
ZReadOnlyQuery1: TZReadOnlyQuery;
ZQuery1: TZQuery;
NILM1: TMenuItem;
Edit1: TMenuItem;
N1: TMenuItem;
Panel2: TPanel;
Label5: TLabel;
Label6: TLabel;
Timer_DateTime: TTimer;
TrayIcon1: TTrayIcon;
tmrExit: TTimer;
FDConnection1: TFDConnection;
FDQuery1: TFDQuery;
FDPhysPgDriverLink1: TFDPhysPgDriverLink;
FDGUIxWaitCursor1: TFDGUIxWaitCursor;
MQTTClient1_old: TMQTTClient;
PageControl1: TPageControl;
TabSheet1: TTabSheet;
TabSheet2: TTabSheet;
ListBox1: TListBox;
Panel1: TPanel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
cxGrid_NILM: TcxGrid;
cxGrid_NILM_Tv: TcxGridTableView;
cxGrid_NILM_Lv: TcxGridLevel;
cxGrid_NILM_TvColumn1: TcxGridColumn;
cxGrid_NILM_TvColumn2: TcxGridColumn;
cxGrid_NILM_TvColumn3: TcxGridColumn;
cxGrid_NILM_TvColumn4: TcxGridColumn;
cxGrid_NILM_TvColumn5: TcxGridColumn;
cxGrid_NILM_TvColumn6: TcxGridColumn;
cxGrid_NILM_TvColumn7: TcxGridColumn;
cxGrid_NILM_TvColumn8: TcxGridColumn;
cxGrid_NILM_TvColumn9: TcxGridColumn;
cxGrid_NILM_TvColumn10: TcxGridColumn;
cxGrid_NILM_TvColumn11: TcxGridColumn;
cxGrid_NILM_TvColumn12: TcxGridColumn;
cxGrid_NILM_TvColumn13: TcxGridColumn;
cxGrid_NILM_TvColumn14: TcxGridColumn;
cxGrid_NILM_TvColumn15: TcxGridColumn;
cxGrid_NILM_TvColumn16: TcxGridColumn;
cxGrid_NILM_TvColumn17: TcxGridColumn;
cxGrid_NILM_TvColumn18: TcxGridColumn;
cxGrid_NILM_TvColumn19: TcxGridColumn;
cxGrid_NILM_TvColumn20: TcxGridColumn;
cxGrid_NILM_TvColumn21: TcxGridColumn;
cxGrid_NILM_TvColumn22: TcxGridColumn;
cxGrid_NILM_TvColumn23: TcxGridColumn;
cxGrid_NILM_TvColumn24: TcxGridColumn;
cxGrid_NILM_TvColumn25: TcxGridColumn;
cxGrid_NILM_TvColumn26: TcxGridColumn;
cxGrid_NILM_TvColumn0: TcxGridColumn;
procedure initTimerTimer(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Connect1Click(Sender: TObject);
procedure Disconnect1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure insertTimerTimer(Sender: TObject);
procedure ListBox1DblClick(Sender: TObject);
procedure ProgramExit1Click(Sender: TObject);
procedure DebugMode1Click(Sender: TObject);
procedure Config1Click(Sender: TObject);
procedure Edit1Click(Sender: TObject);
procedure N1Click(Sender: TObject);
procedure MQTTClient1ClientID(Sender: TObject; var aClientID: UTF8String);
procedure MQTTClient1EnableChange(Sender: TObject);
procedure MQTTClient1Failure(Sender: TObject; aReason: Integer;
var CloseClient: Boolean);
procedure MQTTClient1Mon(Sender: TObject; aStr: string);
procedure MQTTClient1Msg(Sender: TObject; aTopic: UTF8String;
aMessage: AnsiString; aQos: TMQTTQOSType; aRetained: Boolean);
procedure MQTTClient1Offline(Sender: TObject; Graceful: Boolean);
procedure MQTTClient1Online(Sender: TObject);
procedure Timer_DateTimeTimer(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure AppEvtMinimize(Sender: TObject);
procedure tmrExitTimer(Sender: TObject);
procedure TrayIcon1DblClick(Sender: TObject);
private
{ Private declarations }
debug_mode : Boolean;
msg_flaw_stop : boolean;
dumyTopic : string;
debug_mode_count, hubPort : integer;
ExitOk : boolean;
procedure InsertData(topic : string; msg : AnsiString);
procedure NILM_Grid_CLear;
public
//read_gwid : integer;
fIOTGW : array [1..max_gw] of TIOTGW;
fNILM : array [1..max_gw] of TNILM;
appPath : string;
dbIP, dbPW, dbUser, dbSchema : string;
dbIP_PG, dbUser_PG, dbPW_PG, dbSchema_PG : string;
dbPort, dbPort_PG, brokerPort : integer;
mqtt_topic, brokerIP, ClientID, mqtt_user, mqtt_pw : string;
aRetain: Boolean;
old_NilmID : integer;
aQos: TMQTTQOSType;
NILM_ID_List : TList<Integer>;
// NILM_Map: TDictionary<Integer, Integer>;
// NILM_Key, NILM_Value: Integer;
function DB_Connect:Boolean;
function DB_Close:Boolean;
function xAddSqlMark(velStr: String): String;
function xAddSqlDoubleMark(velStr: String): string;
procedure PrintLog(msg, msgType : String);
procedure MQTTParsing(data : AnsiString; aTopic : String);
procedure ClearIOTGW();
procedure SendMQTT_CtrlCommand(sTopic, sMsg : string);
procedure insertSQL(sql : string);
end;
var
frmMain: TfrmMain;
implementation
{$R *.dfm}
uses System.Math, global, uConfigMQTT, uConfigNILM, uDevConfig;
procedure TfrmMain.ClearIOTGW();
var
p, i : integer;
begin
for p:=1 to max_gw do
begin
fIOTGW[p]._TOPIC := '';
for i:=0 to 15 do fIOTGW[p]._DI[i] := false;
for i:=0 to 7 do fIOTGW[p]._DO[i] := false;
for i:=0 to 3 do fIOTGW[p]._AI[i] := 0;
for i:=0 to 9 do fIOTGW[p]._TEMP[i] := 0.0;
for i:=0 to 9 do fIOTGW[p]._HUMID[i] := 0.0;
fIOTGW[p].run_dd := 0;
fIOTGW[p].run_hh := 0;
fIOTGW[p].run_mm := 0;
fIOTGW[p].run_ss := 0;
fNILM[p].idxNo := 0;
fNILM[p]._TOPIC := '';
fNILM[p]._NAME := '';
for i:=1 to 3 do
begin
fNILM[p]._VALUE.PF[i] := 0.0;
fNILM[p]._VALUE.Vrms[i] := 0.0;
fNILM[p]._VALUE.Irms[i] := 0.0;
fNILM[p]._VALUE._Var[i] := 0.0;
fNILM[p]._VALUE.Va[i] := 0.0;
fNILM[p]._VALUE.Pwr[i] := 0.0;
fNILM[p]._VALUE.Gyro[i] := 0.0;
fNILM[p]._VALUE.Accel[i] := 0.0;
end;
fNILM[p]._VALUE.Total_P := 0.0;
fNILM[p]._VALUE.Total_Q := 0.0;
fNILM[p]._VALUE.Total_S := 0.0;
fNILM[p]._VALUE.Total_PF := 0.0;
fNILM[p]._VALUE.wh := 0;
fNILM[p]._VALUE.freq := 0.0;
fNILM[p]._VALUE.rssi := 0;
fNILM[p]._VALUE.seq := 0;
fNILM[p]._VALUE.COMM := 0;
fNILM[p]._VALUE.wire := '';
fNILM[p]._VALUE.TempC := 0;
fNILM[p]._VALUE.TempExt := 0.0;
fNILM[p]._VALUE.Vibration := 0.0;
fNILM[p]._VALUE.TiltAngle := 0.0;
fNILM[p].rcvCount := 0;
fNILM[p].oldRcvCount := 0;
end;
end;
procedure TfrmMain.InsertData(topic : string; msg : AnsiString);
begin
end;
//MQTT 데이터 파싱
procedure TfrmMain.MQTTClient1ClientID(Sender: TObject;
var aClientID: UTF8String);
begin
PrintLog('ClientID :: ' + aClientID, 'SYS');
end;
procedure TfrmMain.MQTTClient1EnableChange(Sender: TObject);
begin
if TMQTTClient(Sender).Enabled then
printlog('Client is enabled.', 'SYS')
else
printlog('Client is disabled.', 'SYS');
end;
procedure TfrmMain.MQTTClient1Failure(Sender: TObject; aReason: Integer;
var CloseClient: Boolean);
begin
printlog('---- Failure Reported ' + FailureNames(aReason), 'SYS');
end;
procedure TfrmMain.MQTTClient1Mon(Sender: TObject; aStr: string);
begin
printlog(aStr, 'SYS');
end;
procedure TfrmMain.MQTTClient1Msg(Sender: TObject; aTopic: UTF8String;
aMessage: AnsiString; aQos: TMQTTQOSType; aRetained: Boolean);
begin
try
if (LeftStr(aMessage,1)='{') and (RightStr(aMessage,1)='}') then
begin
PrintLog('Topic : '+Utf8ToAnsi(aTopic)+', Msg='+aMessage, 'DEBUG');
MQTTParsing(aMessage,Utf8ToAnsi(aTopic));
end else
begin
PrintLog('[Not Entry]Topic : '+Utf8ToAnsi(aTopic), 'DEBUG');
end;
except
on e : exception do
begin
printlog('MQTTClient1Msg Error :: '+e.Message, 'SYS');
end;
end;
end;
procedure TfrmMain.MQTTClient1Offline(Sender: TObject; Graceful: Boolean);
begin
if Graceful then
begin
printlog('Client Gracefully Disconnected.', 'SYS');
end
else
begin
printlog('Client Terminated Unexpectedly.', 'SYS');
end;
end;
procedure TfrmMain.MQTTClient1Online(Sender: TObject);
var
s: TStringList;
begin
printlog('Client is online.', 'SYS');
s := TStringList.Create;
s.AddObject(mqtt_topic, TObject(aQos));
MQTTClient1.Subscribe(s);
s.Free;
end;
procedure TfrmMain.MQTTParsing(data : AnsiString; aTopic : String);
var
tempTopic_list : TStringList;
pf, Vrms, Irms, Var_, Va, Pwr: Single;
nilmID, ch, k, pIdx : integer;
grid_rowck : integer;
devStr, numStr: string;
ch_c : char;
JSONObject, ChObj, TotObj, SlaveObj : TJSONObject;
ChArr, SlaveArr : TJSONArray;
jvCh, jvTot: TJSONValue;
hasRealVoltage, hasRealPower, hasCurrent : Boolean;
sumP, sumQ, sumS, maxI, nomV, assPF : Double;
function GetValNum(const AObj: TJSONObject; const AKey: string; ADefault: Double = 0.0): Double;
var LVal: TJSONValue;
begin
Result := ADefault;
if AObj = nil then Exit;
LVal := AObj.GetValue(AKey);
if Assigned(LVal) and (not (LVal is TJSONNull)) then
Result := StrToFloatDef(LVal.Value, ADefault);
end;
function GetValInt(const AObj: TJSONObject; const AKey: string; ADefault: Integer = 0): Integer;
var LVal: TJSONValue;
begin
Result := ADefault;
if AObj = nil then Exit;
LVal := AObj.GetValue(AKey);
if Assigned(LVal) and (not (LVal is TJSONNull)) then
Result := StrToIntDef(LVal.Value, ADefault);
end;
function GetValInt64(const AObj: TJSONObject; const AKey: string; ADefault: Int64 = 0): Int64;
var LVal: TJSONValue;
begin
Result := ADefault;
if AObj = nil then Exit;
LVal := AObj.GetValue(AKey);
if Assigned(LVal) and (not (LVal is TJSONNull)) then
Result := StrToInt64Def(LVal.Value, ADefault);
end;
function GetValStr(const AObj: TJSONObject; const AKey, ADefault: string): string;
var LVal: TJSONValue;
begin
Result := ADefault;
if AObj = nil then Exit;
LVal := AObj.GetValue(AKey);
if Assigned(LVal) and (not (LVal is TJSONNull)) then
Result := LVal.Value;
end;
begin
try
if Trim(data) = '' then Exit;
InsertData(aTopic, data);
JSONObject := TJSONObject.ParseJSONValue(data) as TJSONObject;
if JSONObject = nil then Exit;
tempTopic_list := TStringList.Create;
try
nilmID := 0;
// 1순위: JSON의 dev 필드 확인 (예: "NILM_001", "NILM_032")
devStr := GetValStr(JSONObject, 'dev', '');
if devStr <> '' then
begin
numStr := '';
for ch_c in devStr do
if ch_c in ['0'..'9'] then numStr := numStr + ch_c;
nilmID := StrToIntDef(numStr, 0);
end;
// 2순위: 토픽 경로에서 추출
if nilmID <= 0 then
begin
Strsplit('/', aTopic, tempTopic_list);
if tempTopic_list.Count > 0 then
begin
if (tempTopic_list.Strings[tempTopic_list.Count - 1] = 'status') or
(tempTopic_list.Strings[tempTopic_list.Count - 1] = 'event') then
begin
if tempTopic_list.Count > 1 then
nilmID := StrToIntDef(tempTopic_list.Strings[tempTopic_list.Count - 2], 0);
end
else
begin
nilmID := StrToIntDef(tempTopic_list.Strings[tempTopic_list.Count - 1], 0);
end;
end;
end;
// 특수 토픽 (status, gateway, event) 처리
if aTopic.EndsWith('/status') then
begin
printlog(Format('[노드상태] 장비 %d: online=%s, loss_rate=%s',
[nilmID, GetValStr(JSONObject, 'online', ''), GetValStr(JSONObject, 'loss_rate', '0')]), 'SYS');
Exit;
end
else if aTopic.EndsWith('/gateway') then
begin
printlog(Format('[게이트웨이] %s: online=%s, nodes=%d/%d',
[GetValStr(JSONObject, 'gw', ''), GetValStr(JSONObject, 'online', ''),
GetValInt(JSONObject, 'nodes_online', 0), GetValInt(JSONObject, 'nodes_total', 0)]), 'SYS');
Exit;
end
else if aTopic.EndsWith('/event') then
begin
printlog(Format('[ALARM] 장비 %d: %s (코드:%d, 값:%.2f)',
[nilmID, GetValStr(JSONObject, 'name', ''), GetValInt(JSONObject, 'code', 0), GetValNum(JSONObject, 'value', 0.0)]), 'SYS');
Exit;
end;
if (nilmID <= 0) or (nilmID > max_gw) or (fNILM[nilmID].idxNo <= 0) then Exit;
grid_rowck := NILM_ID_List.IndexOf(nilmID);
// =========================================================================
// CASE 1: 최신 표준 단일 규격 (ch 배열 및 total 객체)
// =========================================================================
jvCh := JSONObject.GetValue('ch');
if (jvCh <> nil) and (jvCh is TJSONArray) then
begin
ChArr := jvCh as TJSONArray;
fNILM[nilmID]._VALUE.seq := GetValInt(JSONObject, 'seq', 0);
fNILM[nilmID]._VALUE.COMM := GetValInt(JSONObject, 'COMM', 0);
fNILM[nilmID]._VALUE.rssi := GetValInt(JSONObject, 'rssi', 0);
fNILM[nilmID]._VALUE.wire := GetValStr(JSONObject, 'wire', '3P4W');
fNILM[nilmID]._VALUE.freq := GetValNum(JSONObject, 'freq', 60.0);
fNILM[nilmID]._VALUE.wh := GetValInt64(JSONObject, 'wh', 0);
for k := 0 to Min(2, ChArr.Count - 1) do
begin
if (ChArr.Items[k] <> nil) and (ChArr.Items[k] is TJSONObject) then
begin
ChObj := ChArr.Items[k] as TJSONObject;
pIdx := k + 1; // 1..3
fNILM[nilmID]._VALUE.Vrms[pIdx] := GetValNum(ChObj, 'v', 0.0);
fNILM[nilmID]._VALUE.Irms[pIdx] := GetValNum(ChObj, 'i', 0.0);
fNILM[nilmID]._VALUE.Pwr[pIdx] := GetValNum(ChObj, 'p', 0.0);
fNILM[nilmID]._VALUE._Var[pIdx] := GetValNum(ChObj, 'q', 0.0);
fNILM[nilmID]._VALUE.Va[pIdx] := GetValNum(ChObj, 's', 0.0);
fNILM[nilmID]._VALUE.PF[pIdx] := GetValNum(ChObj, 'pf', 0.0);
end;
end;
jvTot := JSONObject.GetValue('total');
if (jvTot <> nil) and (jvTot is TJSONObject) then
begin
TotObj := jvTot as TJSONObject;
fNILM[nilmID]._VALUE.Total_P := GetValNum(TotObj, 'p', 0.0);
fNILM[nilmID]._VALUE.Total_Q := GetValNum(TotObj, 'q', 0.0);
fNILM[nilmID]._VALUE.Total_S := GetValNum(TotObj, 's', 0.0);
fNILM[nilmID]._VALUE.Total_PF := GetValNum(TotObj, 'pf', 0.0);
end;
// 환경/센서 데이터
fNILM[nilmID]._VALUE.TempC := GetValNum(JSONObject, 'temperature', GetValNum(JSONObject, 'TempC', fNILM[nilmID]._VALUE.TempC));
fNILM[nilmID]._VALUE.TempExt := GetValNum(JSONObject, 'tempExt', 0.0);
fNILM[nilmID]._VALUE.Accel[1] := GetValNum(JSONObject, 'accX', GetValNum(JSONObject, 'aX', fNILM[nilmID]._VALUE.Accel[1]));
fNILM[nilmID]._VALUE.Accel[2] := GetValNum(JSONObject, 'accY', GetValNum(JSONObject, 'aY', fNILM[nilmID]._VALUE.Accel[2]));
fNILM[nilmID]._VALUE.Accel[3] := GetValNum(JSONObject, 'accZ', GetValNum(JSONObject, 'aZ', fNILM[nilmID]._VALUE.Accel[3]));
fNILM[nilmID]._VALUE.Vibration := GetValNum(JSONObject, 'vibration', 0.0);
fNILM[nilmID]._VALUE.Gyro[1] := GetValNum(JSONObject, 'gyroX', GetValNum(JSONObject, 'gX', fNILM[nilmID]._VALUE.Gyro[1]));
fNILM[nilmID]._VALUE.Gyro[2] := GetValNum(JSONObject, 'gyroY', GetValNum(JSONObject, 'gY', fNILM[nilmID]._VALUE.Gyro[2]));
fNILM[nilmID]._VALUE.Gyro[3] := GetValNum(JSONObject, 'gyroZ', GetValNum(JSONObject, 'gZ', fNILM[nilmID]._VALUE.Gyro[3]));
fNILM[nilmID]._VALUE.TiltAngle := GetValNum(JSONObject, 'tiltAngle', 0.0);
end
// =========================================================================
// CASE 2: 하위 호환 slave_data 구조
// =========================================================================
else if JSONObject.GetValue('slave_data') <> nil then
begin
SlaveArr := JSONObject.GetValue<TJSONArray>('slave_data');
if (SlaveArr <> nil) and (SlaveArr.Count > 0) and (SlaveArr.Items[0] is TJSONObject) then
begin
SlaveObj := SlaveArr.Items[0] as TJSONObject;
fNILM[nilmID]._VALUE.seq := GetValInt(SlaveObj, 'seq', 0);
fNILM[nilmID]._VALUE.COMM := GetValInt(SlaveObj, 'COMM', 0);
fNILM[nilmID]._VALUE.rssi := GetValInt(SlaveObj, 'rssi', 0);
fNILM[nilmID]._VALUE.wire := GetValStr(SlaveObj, 'wire', '3P4W');
fNILM[nilmID]._VALUE.freq := GetValNum(SlaveObj, 'frequency', 60.0);
fNILM[nilmID]._VALUE.wh := GetValInt64(SlaveObj, 'wh', 0);
// A상 (CH 1)
fNILM[nilmID]._VALUE.PF[1] := GetValNum(SlaveObj, 'power_factor_a', GetValNum(SlaveObj, 'pfA', 0.0));
fNILM[nilmID]._VALUE.Vrms[1] := GetValNum(SlaveObj, 'vrms_a', GetValNum(SlaveObj, 'voltageA', 0.0));
fNILM[nilmID]._VALUE.Irms[1] := GetValNum(SlaveObj, 'irms_a', GetValNum(SlaveObj, 'currentA', 0.0));
fNILM[nilmID]._VALUE.Pwr[1] := GetValNum(SlaveObj, 'active_power_a', GetValNum(SlaveObj, 'wA', 0.0));
fNILM[nilmID]._VALUE._Var[1] := GetValNum(SlaveObj, 'reactive_power_a', GetValNum(SlaveObj, 'Var_A', 0.0));
fNILM[nilmID]._VALUE.Va[1] := GetValNum(SlaveObj, 'apparent_power_a', GetValNum(SlaveObj, 'Va_A', 0.0));
// B상 (CH 2)
if fNILM[nilmID]._VALUE.wire <> '3P3W' then
begin
fNILM[nilmID]._VALUE.PF[2] := GetValNum(SlaveObj, 'power_factor_b', GetValNum(SlaveObj, 'pfB', 0.0));
fNILM[nilmID]._VALUE.Vrms[2] := GetValNum(SlaveObj, 'vrms_b', GetValNum(SlaveObj, 'voltageB', 0.0));
fNILM[nilmID]._VALUE.Irms[2] := GetValNum(SlaveObj, 'irms_b', GetValNum(SlaveObj, 'currentB', 0.0));
fNILM[nilmID]._VALUE.Pwr[2] := GetValNum(SlaveObj, 'active_power_b', GetValNum(SlaveObj, 'wB', 0.0));
fNILM[nilmID]._VALUE._Var[2] := GetValNum(SlaveObj, 'reactive_power_b', GetValNum(SlaveObj, 'Var_B', 0.0));
fNILM[nilmID]._VALUE.Va[2] := GetValNum(SlaveObj, 'apparent_power_b', GetValNum(SlaveObj, 'Va_B', 0.0));
end;
// C상 (CH 3)
fNILM[nilmID]._VALUE.PF[3] := GetValNum(SlaveObj, 'power_factor_c', GetValNum(SlaveObj, 'pfC', 0.0));
fNILM[nilmID]._VALUE.Vrms[3] := GetValNum(SlaveObj, 'vrms_c', GetValNum(SlaveObj, 'voltageC', 0.0));
fNILM[nilmID]._VALUE.Irms[3] := GetValNum(SlaveObj, 'irms_c', GetValNum(SlaveObj, 'currentC', 0.0));
fNILM[nilmID]._VALUE.Pwr[3] := GetValNum(SlaveObj, 'active_power_c', GetValNum(SlaveObj, 'wC', 0.0));
fNILM[nilmID]._VALUE._Var[3] := GetValNum(SlaveObj, 'reactive_power_c', GetValNum(SlaveObj, 'Var_C', 0.0));
fNILM[nilmID]._VALUE.Va[3] := GetValNum(SlaveObj, 'apparent_power_c', GetValNum(SlaveObj, 'Va_C', 0.0));
// Total
fNILM[nilmID]._VALUE.Total_P := GetValNum(SlaveObj, 'total_p', 0.0);
fNILM[nilmID]._VALUE.Total_Q := GetValNum(SlaveObj, 'total_q', 0.0);
fNILM[nilmID]._VALUE.Total_S := GetValNum(SlaveObj, 'total_s', 0.0);
fNILM[nilmID]._VALUE.Total_PF := GetValNum(SlaveObj, 'total_pf', 0.0);
// 환경/센서
fNILM[nilmID]._VALUE.TempC := GetValNum(SlaveObj, 'temperature', GetValNum(SlaveObj, 'TempC', fNILM[nilmID]._VALUE.TempC));
fNILM[nilmID]._VALUE.Accel[1] := GetValNum(SlaveObj, 'accX', GetValNum(SlaveObj, 'aX', fNILM[nilmID]._VALUE.Accel[1]));
fNILM[nilmID]._VALUE.Accel[2] := GetValNum(SlaveObj, 'accY', GetValNum(SlaveObj, 'aY', fNILM[nilmID]._VALUE.Accel[2]));
fNILM[nilmID]._VALUE.Accel[3] := GetValNum(SlaveObj, 'accZ', GetValNum(SlaveObj, 'aZ', fNILM[nilmID]._VALUE.Accel[3]));
fNILM[nilmID]._VALUE.Gyro[1] := GetValNum(SlaveObj, 'gyroX', GetValNum(SlaveObj, 'gX', fNILM[nilmID]._VALUE.Gyro[1]));
fNILM[nilmID]._VALUE.Gyro[2] := GetValNum(SlaveObj, 'gyroY', GetValNum(SlaveObj, 'gY', fNILM[nilmID]._VALUE.Gyro[2]));
fNILM[nilmID]._VALUE.Gyro[3] := GetValNum(SlaveObj, 'gyroZ', GetValNum(SlaveObj, 'gZ', fNILM[nilmID]._VALUE.Gyro[3]));
end;
end
// =========================================================================
// CASE 3: 구형 CH 분할 포맷 ("CH": "01", "02", "03")
// =========================================================================
else if JSONObject.GetValue('CH') <> nil then
begin
ch := StrToIntDef(JSONObject.GetValue('CH').Value, 0);
case ch of
1, 2, 3:
begin
pf := GetValNum(JSONObject, 'PF', 0.0);
Vrms := GetValNum(JSONObject, 'Vrms', 0.0);
Irms := GetValNum(JSONObject, 'Irms', 0.0);
Var_ := GetValNum(JSONObject, 'Var_', 0.0);
Va := GetValNum(JSONObject, 'Va', 0.0);
Pwr := GetValNum(JSONObject, 'Pwr', 0.0);
fNILM[nilmID]._VALUE.PF[ch] := pf;
fNILM[nilmID]._VALUE.Vrms[ch] := Vrms;
fNILM[nilmID]._VALUE.Irms[ch] := Irms;
fNILM[nilmID]._VALUE._Var[ch] := Var_;
fNILM[nilmID]._VALUE.Va[ch] := Va;
fNILM[nilmID]._VALUE.Pwr[ch] := Pwr;
end;
4: // MPU 센서 또는 03 채널
begin
fNILM[nilmID]._VALUE.Gyro[1] := GetValNum(JSONObject, 'gX', fNILM[nilmID]._VALUE.Gyro[1]);
fNILM[nilmID]._VALUE.Gyro[2] := GetValNum(JSONObject, 'gY', fNILM[nilmID]._VALUE.Gyro[2]);
fNILM[nilmID]._VALUE.Gyro[3] := GetValNum(JSONObject, 'gZ', fNILM[nilmID]._VALUE.Gyro[3]);
fNILM[nilmID]._VALUE.Accel[1] := GetValNum(JSONObject, 'aX', fNILM[nilmID]._VALUE.Accel[1]);
fNILM[nilmID]._VALUE.Accel[2] := GetValNum(JSONObject, 'aY', fNILM[nilmID]._VALUE.Accel[2]);
fNILM[nilmID]._VALUE.Accel[3] := GetValNum(JSONObject, 'aZ', fNILM[nilmID]._VALUE.Accel[3]);
fNILM[nilmID]._VALUE.TempC := GetValNum(JSONObject, 'TempC', fNILM[nilmID]._VALUE.TempC);
end;
end;
end;
// =========================================================================
// 가상 전력 추정 계산 (1-CT 전류 전용 환경 대응)
// =========================================================================
hasRealVoltage := (fNILM[nilmID]._VALUE.Vrms[1] > 0) or (fNILM[nilmID]._VALUE.Vrms[2] > 0) or (fNILM[nilmID]._VALUE.Vrms[3] > 0);
hasRealPower := (fNILM[nilmID]._VALUE.Pwr[1] > 0) or (fNILM[nilmID]._VALUE.Pwr[2] > 0) or (fNILM[nilmID]._VALUE.Pwr[3] > 0) or (fNILM[nilmID]._VALUE.Total_P > 0);
hasCurrent := (fNILM[nilmID]._VALUE.Irms[1] > 0) or (fNILM[nilmID]._VALUE.Irms[2] > 0) or (fNILM[nilmID]._VALUE.Irms[3] > 0);
if hasCurrent and (not hasRealVoltage) and (not hasRealPower) then
begin
nomV := 220.0;
assPF := 0.90;
sumP := 0.0; sumQ := 0.0; sumS := 0.0; maxI := 0.0;
for k := 1 to 3 do
begin
if fNILM[nilmID]._VALUE.Irms[k] > 0 then
begin
fNILM[nilmID]._VALUE.Vrms[k] := nomV;
fNILM[nilmID]._VALUE.PF[k] := assPF;
fNILM[nilmID]._VALUE.Va[k] := nomV * fNILM[nilmID]._VALUE.Irms[k];
fNILM[nilmID]._VALUE.Pwr[k] := fNILM[nilmID]._VALUE.Va[k] * assPF;
fNILM[nilmID]._VALUE._Var[k] := Sqrt(Max(Sqr(fNILM[nilmID]._VALUE.Va[k]) - Sqr(fNILM[nilmID]._VALUE.Pwr[k]), 0.0));
sumP := sumP + fNILM[nilmID]._VALUE.Pwr[k];
sumQ := sumQ + fNILM[nilmID]._VALUE._Var[k];
sumS := sumS + fNILM[nilmID]._VALUE.Va[k];
if fNILM[nilmID]._VALUE.Irms[k] > maxI then maxI := fNILM[nilmID]._VALUE.Irms[k];
end;
end;
fNILM[nilmID]._VALUE.Total_P := sumP;
fNILM[nilmID]._VALUE.Total_Q := sumQ;
fNILM[nilmID]._VALUE.Total_S := sumS;
fNILM[nilmID]._VALUE.Total_PF := assPF;
end;
// =========================================================================
// 3P3W / 3P4W Total 전력 자동 합산 보정
// =========================================================================
if (fNILM[nilmID]._VALUE.Total_P = 0) and (fNILM[nilmID]._VALUE.Pwr[1] > 0) then
begin
if SameText(fNILM[nilmID]._VALUE.wire, '3P3W') then
begin
fNILM[nilmID]._VALUE.Total_P := fNILM[nilmID]._VALUE.Pwr[1] + fNILM[nilmID]._VALUE.Pwr[3];
fNILM[nilmID]._VALUE.Total_Q := fNILM[nilmID]._VALUE._Var[1] + fNILM[nilmID]._VALUE._Var[3];
end
else
begin
fNILM[nilmID]._VALUE.Total_P := fNILM[nilmID]._VALUE.Pwr[1] + fNILM[nilmID]._VALUE.Pwr[2] + fNILM[nilmID]._VALUE.Pwr[3];
fNILM[nilmID]._VALUE.Total_Q := fNILM[nilmID]._VALUE._Var[1] + fNILM[nilmID]._VALUE._Var[2] + fNILM[nilmID]._VALUE._Var[3];
end;
fNILM[nilmID]._VALUE.Total_S := Sqrt(Sqr(fNILM[nilmID]._VALUE.Total_P) + Sqr(fNILM[nilmID]._VALUE.Total_Q));
if fNILM[nilmID]._VALUE.Total_S > 0 then
fNILM[nilmID]._VALUE.Total_PF := fNILM[nilmID]._VALUE.Total_P / fNILM[nilmID]._VALUE.Total_S;
end;
// 수신 카운트 증가
fNILM[nilmID].rcvCount := fNILM[nilmID].rcvCount + 1;
if fNILM[nilmID].rcvCount > 65535 then fNILM[nilmID].rcvCount := 1;
// 라벨 캡션 갱신
Label2.Caption := Format('[ID : %d / CH : 01] PF : %.3f, Vrms : %.3f, Irms : %.3f, Var : %.3f, Va : %.3f, Pwr : %.3f',
[nilmID, fNILM[nilmID]._VALUE.PF[1], fNILM[nilmID]._VALUE.Vrms[1], fNILM[nilmID]._VALUE.Irms[1],
fNILM[nilmID]._VALUE._Var[1], fNILM[nilmID]._VALUE.Va[1], fNILM[nilmID]._VALUE.Pwr[1]]);
Label3.Caption := Format('[ID : %d / CH : 02] PF : %.3f, Vrms : %.3f, Irms : %.3f, Var : %.3f, Va : %.3f, Pwr : %.3f',
[nilmID, fNILM[nilmID]._VALUE.PF[2], fNILM[nilmID]._VALUE.Vrms[2], fNILM[nilmID]._VALUE.Irms[2],
fNILM[nilmID]._VALUE._Var[2], fNILM[nilmID]._VALUE.Va[2], fNILM[nilmID]._VALUE.Pwr[2]]);
Label4.Caption := Format('[ID : %d / MPU] gX : %.3f, gY : %.3f, gZ : %.3f, aX : %.3f, aY : %.3f, aZ : %.3f, Temp : %.2f',
[nilmID, fNILM[nilmID]._VALUE.Gyro[1], fNILM[nilmID]._VALUE.Gyro[2], fNILM[nilmID]._VALUE.Gyro[3],
fNILM[nilmID]._VALUE.Accel[1], fNILM[nilmID]._VALUE.Accel[2], fNILM[nilmID]._VALUE.Accel[3], fNILM[nilmID]._VALUE.TempC]);
// cxGrid 실시간 반영
if (PageControl1.TabIndex = 0) and (grid_rowck >= 0) then
with cxGrid_NILM_Tv.DataController do
begin
try
BeginUpdate;
// CH 1
Values[grid_rowck, cxGrid_NILM_TvColumn1.Index] := Format('%.3f', [fNILM[nilmID]._VALUE.PF[1]]);
Values[grid_rowck, cxGrid_NILM_TvColumn2.Index] := Format('%.3f', [fNILM[nilmID]._VALUE.Vrms[1]]);
Values[grid_rowck, cxGrid_NILM_TvColumn3.Index] := Format('%.3f', [fNILM[nilmID]._VALUE.Irms[1]]);
Values[grid_rowck, cxGrid_NILM_TvColumn4.Index] := Format('%.3f', [fNILM[nilmID]._VALUE._Var[1]]);
Values[grid_rowck, cxGrid_NILM_TvColumn5.Index] := Format('%.3f', [fNILM[nilmID]._VALUE.Va[1]]);
Values[grid_rowck, cxGrid_NILM_TvColumn6.Index] := Format('%.3f', [fNILM[nilmID]._VALUE.Pwr[1]]);
// CH 2
Values[grid_rowck, cxGrid_NILM_TvColumn7.Index] := Format('%.3f', [fNILM[nilmID]._VALUE.PF[2]]);
Values[grid_rowck, cxGrid_NILM_TvColumn8.Index] := Format('%.3f', [fNILM[nilmID]._VALUE.Vrms[2]]);
Values[grid_rowck, cxGrid_NILM_TvColumn9.Index] := Format('%.3f', [fNILM[nilmID]._VALUE.Irms[2]]);
Values[grid_rowck, cxGrid_NILM_TvColumn10.Index] := Format('%.3f', [fNILM[nilmID]._VALUE._Var[2]]);
Values[grid_rowck, cxGrid_NILM_TvColumn11.Index] := Format('%.3f', [fNILM[nilmID]._VALUE.Va[2]]);
Values[grid_rowck, cxGrid_NILM_TvColumn12.Index] := Format('%.3f', [fNILM[nilmID]._VALUE.Pwr[2]]);
// CH 3
Values[grid_rowck, cxGrid_NILM_TvColumn13.Index] := Format('%.3f', [fNILM[nilmID]._VALUE.PF[3]]);
Values[grid_rowck, cxGrid_NILM_TvColumn14.Index] := Format('%.3f', [fNILM[nilmID]._VALUE.Vrms[3]]);
Values[grid_rowck, cxGrid_NILM_TvColumn15.Index] := Format('%.3f', [fNILM[nilmID]._VALUE.Irms[3]]);
Values[grid_rowck, cxGrid_NILM_TvColumn16.Index] := Format('%.3f', [fNILM[nilmID]._VALUE._Var[3]]);
Values[grid_rowck, cxGrid_NILM_TvColumn17.Index] := Format('%.3f', [fNILM[nilmID]._VALUE.Va[3]]);
Values[grid_rowck, cxGrid_NILM_TvColumn18.Index] := Format('%.3f', [fNILM[nilmID]._VALUE.Pwr[3]]);
// MPU 및 센서
Values[grid_rowck, cxGrid_NILM_TvColumn19.Index] := Format('%.3f', [fNILM[nilmID]._VALUE.Gyro[1]]);
Values[grid_rowck, cxGrid_NILM_TvColumn20.Index] := Format('%.3f', [fNILM[nilmID]._VALUE.Gyro[2]]);
Values[grid_rowck, cxGrid_NILM_TvColumn21.Index] := Format('%.3f', [fNILM[nilmID]._VALUE.Gyro[3]]);
Values[grid_rowck, cxGrid_NILM_TvColumn22.Index] := Format('%.3f', [fNILM[nilmID]._VALUE.Accel[1]]);
Values[grid_rowck, cxGrid_NILM_TvColumn23.Index] := Format('%.3f', [fNILM[nilmID]._VALUE.Accel[2]]);
Values[grid_rowck, cxGrid_NILM_TvColumn24.Index] := Format('%.3f', [fNILM[nilmID]._VALUE.Accel[3]]);
Values[grid_rowck, cxGrid_NILM_TvColumn25.Index] := Format('%.3f', [fNILM[nilmID]._VALUE.TempC]);
// 시각
Values[grid_rowck, cxGrid_NILM_TvColumn26.Index] := FormatDateTime('yymmdd hhnnss', Now);
finally
EndUpdate;
end;
end;
finally
tempTopic_list.Free;
JSONObject.Free;
end;
except
on e: Exception do
begin
printlog('MQTTParsing Error :: ' + e.Message, 'SYS');
end;
end;
end;
procedure TfrmMain.PrintLog(msg, msgType : string);
var
f : TextFile;
log: TStringList;
i : integer;
logfile, buf : string;
begin
if ListBox1.Items.Count >= 300 then ListBox1.Items.Clear;
if msgType = 'DEBUG' then
begin
if debug_mode then
begin
if not msg_flaw_stop then ListBox1.Items.Insert(0, FormatDateTime('hh:nn:ss :: ',now)+msg);
end;
end else if msgType = 'SYS' then
begin
ListBox1.Items.Insert(0, FormatDateTime('hh:nn:ss :: ',now)+msg);
logfile := '';
logfile := appPath+'log\'+formatdatetime('yyyymmddhh',now())+'.log';
if FileExists(logfile) then
begin
log := TStringList.Create;
AssignFile(f, logfile);
reset(f);
while not eof(f) do
begin
ReadLn(f, buf);
log.Add(buf);
end;
log.add(FormatDateTime('hh:nn:ss :: ',now)+msg);
CloseFile(F);
AssignFile(f, logfile);
rewrite(f);
for i := 0 to log.Count - 1 do
begin
WriteLn(f, log.strings[i]);
end;
CloseFile(F);
log.Free;
end else
begin
log := TStringList.Create;
log.add(FormatDateTime('hh:nn:ss :: ',now)+msg);
AssignFile(f, logfile);
rewrite(f);
for i := 0 to log.Count - 1 do
begin
WriteLn(f, log.strings[i]);
end;
CloseFile(F);
log.Free;
end;
end;
end;
procedure TfrmMain.initTimerTimer(Sender: TObject);
var
ini : TInifile;
pwd : string;
begin
old_NilmID := 0;
debug_mode := false;
debug_mode_count := 0;
msg_flaw_stop := false;
ListBox1.Clear;
mqtt_topic := '';
mqtt_topic := 'QST/NILM/LVDT/#';
pwd := '';
pwd := appPath+'NILM_Manager.ini';
if FileExists(pwd) then
begin
ini := TInifile.Create(pwd);
with ini do
begin
mqtt_topic := ReadString('MQTT','TOPIC',mqtt_topic);
brokerIP := ReadString('MQTT','BrokerIP','183.111.125.203');
brokerPort := ReadInteger('MQTT','BrokerPort',1883);
ClientID := ReadString('MQTT','ClientID','NILM_1st');
mqtt_user := ReadString('MQTT','User','qsentech');
mqtt_pw := ReadString('MQTT','Password','qsentech!1233');
dbIP := ReadString('DATABASE','IP','192.168.200.199');
dbUser := ReadString('DATABASE','User','root');
dbPW := ReadString('DATABASE','PW','1233');
dbSchema := ReadString('DATABASE','Schema','nilm');
dbPort := ReadInteger('DATABASE','Port',3306);
dbIP_PG := ReadString('DATABASE_PG','IP','192.168.200.199');
dbUser_PG := ReadString('DATABASE_PG','User','root');
dbPW_PG := ReadString('DATABASE_PG','PW','54323');
dbSchema_PG := ReadString('DATABASE_PG','Schema','neol');
dbPort_PG := ReadInteger('DATABASE_PG','Port',3306);
hubPort := ReadInteger('MQTT_HUB','Port',6969);
end;
ini.Free;
end;
Statusbar1.Panels.Items[2].Text := format('%d',[MQTTClient1.Port]);
Statusbar1.Panels.Items[3].Text := mqtt_topic;
MQTTClient1.Activate(false);
Sleep(300);
randomize();
MQTTClient1.ClientID := ClientID+'_'+inttostr(random(999999));
MQTTClient1.Host := brokerIP;
MQTTClient1.Port := brokerPort;
MQTTClient1.Username := mqtt_user;
MQTTClient1.Password := mqtt_pw;
MQTTClient1.Activate(true);
// QSENTECH_NILM 서버
if ZConnection1.Connected then ZConnection1.disConnect();
Sleep(300);
ZConnection1.HostName := dbIP;
ZConnection1.Port := dbPort;
ZConnection1.User := dbUser;
ZConnection1.Password := dbPW;
ZConnection1.Database := dbSchema;
try
if not ZConnection1.Connected then ZConnection1.Connect();
except
on e : exception do
begin
printlog('Database Connect Error :: '+e.Message, 'DB');
end;
end;
{
// NEOL_NILM 서버
if not DB_Connect then begin
printlog('Database Connect Error :: PG', 'DB');
end;
}
frmNILM.ShowNILM();
if NILM_ID_List.Count > 0 then begin
NILM_Grid_CLear;
end;
frmDevConfig.ShowDev();
insertTimer.Enabled := True;
initTimer.Enabled := false;
AppEvtMinimize(self);
end;
procedure TfrmMain.NILM_Grid_CLear;
var
row_ck, i : Integer;
begin
with cxGrid_NILM_Tv.DataController do begin
try
BeginUpdate;
RecordCount := 0;
finally
EndUpdate;
end;
try
BeginUpdate;
for I := 0 to NILM_ID_List.Count-1 do begin
row_ck := AppendRecord;
Values[row_ck,cxGrid_NILM_TvColumn0.Index] := NILM_ID_List[i];
end;
finally
EndUpdate;
end;
end;
end;
procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if insertTimer.Enabled then insertTimer.Enabled := False;
if Timer_DateTime.Enabled then Timer_DateTime.Enabled := False;
MQTTClient1.Activate(false);
if ZConnection1.Connected then ZConnection1.disConnect();
NILM_ID_List.Free;
// NILM_Map.Free;
end;
procedure TfrmMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if ExitOk then begin
CanClose := true;
end else begin
CanClose := false;
case MessageBox(handle, '"예(Y)"를 클릭하면, MQTT Client가 트레이로 최소화 됩니다.'+#$0D#$0A#$0D#$0A+'"아니오(N)"를 클릭하면 프로그램이 종료됩니다. ', 'MQTT Client :: 트레이로 최소화 할까요?', MB_YESNOCANCEL) of
ID_YES : begin
TrayIcon1.BalloonTitle := 'MQTT Client 화면을 다시 보려면...';
TrayIcon1.BalloonHint := '트레이 아이콘을 더블클릭하세요.';
//TrayIcon1.BalloonFlags := bfInfo;
AppEvtMinimize(self);
end;
ID_NO : begin
//종료 타이머 시작하고 끝나면 ExitOk~
tmrExit.Tag := 0;
tmrExit.Enabled := true;
end;
end;//case..
end;//if~
end;
procedure TfrmMain.AppEvtMinimize(Sender: TObject);
begin
Hide;
WindowState := wsMinimized;
TrayIcon1.Visible := True;
TrayIcon1.Animate := True;
TrayIcon1.ShowBalloonHint;
end;
procedure TfrmMain.Connect1Click(Sender: TObject);
begin
MQTTClient1.Activate(false);
sleep(300);
MQTTClient1.Activate(true);
end;
procedure TfrmMain.Disconnect1Click(Sender: TObject);
begin
MQTTClient1.Activate(false);
end;
procedure TfrmMain.FormCreate(Sender: TObject);
begin
NILM_ID_List := TList<Integer>.Create;
// NILM_Map := TDictionary<Integer, Integer>.Create;
Label2.Caption := '';
Label3.Caption := '';
Label4.Caption := '';
PageControl1.TabIndex := 1;
appPath := '';
appPath := ExtractFilePath(Application.ExeName);
if not DirectoryExists(appPath + 'log') then
if not CreateDir(appPath + 'log') then
raise Exception.Create('Cannot create ' + appPath + 'log');
ClearIOTGW();
Label6.Caption := format('시작 시간 : %s', [FormatDateTime('YYYY-MM-DD HH:mm:ss', now)]);
end;
procedure TfrmMain.SendMQTT_CtrlCommand(sTopic, sMsg : string);
var
pTopic : UTF8String;
begin
pTopic := '';
pTopic := sTopic;
MQTTClient1.Publish(pTopic, sMsg, aQos, false);
end;
procedure TfrmMain.Timer_DateTimeTimer(Sender: TObject);
begin
Label5.Caption := FormatDateTime('YYYY-MM-DD HH:mm:ss', now);
end;
procedure TfrmMain.tmrExitTimer(Sender: TObject);
begin
case tmrExit.Tag of
0 : begin
tmrExit.Tag := tmrExit.Tag+1;
end;
1..4 : tmrExit.Tag := tmrExit.Tag+1;
5 : begin
tmrExit.Tag := tmrExit.Tag+1;
tmrExit.Enabled := false;
ExitOk := true;
Close;
end;
end;//case..
end;
procedure TfrmMain.TrayIcon1DblClick(Sender: TObject);
begin
TrayIcon1.Visible := False;
Show;
WindowState := wsNormal;
Application.BringToFront;
end;
procedure TfrmMain.insertSQL(sql : string);
begin
try
{ 인서트마다 재접속 제거 20250717
try
if not ZConnection1.Connected then ZConnection1.Connect();
if ZConnection1.Connected then
begin
ZQuery1.Active := false;
ZQuery1.SQL.Clear;
ZQuery1.SQL.Add(sql);
ZQuery1.ExecSQL;
end;
finally
if ZConnection1.Connected then ZConnection1.Disconnect;
end;
}
if not ZConnection1.Connected then ZConnection1.Connect();
if ZConnection1.Connected then
begin
ZQuery1.Active := false;
ZQuery1.SQL.Clear;
ZQuery1.SQL.Add(sql);
ZQuery1.ExecSQL;
end;
except
on e : exception do
begin
printlog('[insertSQL()]Database Connect Error :: '+e.Message, 'DB');
end;
end;
end;
procedure TfrmMain.insertTimerTimer(Sender: TObject);
var
pMsg, S, sql : string;
pTopic : UTF8String;
i, p : integer;
begin
if debug_mode then
begin
Statusbar1.Panels.Items[0].Text := 'DEBUG';
Inc(debug_mode_count, 1);
if debug_mode_count > 1800 then // Debug Mode는 30분만 동작한다. CPU 점유률 때문에, 24시간 돌리지 않는다.
begin
debug_mode_count := 0;
debug_mode := false;
DebugMode1.Checked := debug_mode;
end;
end else
begin
Statusbar1.Panels.Items[0].Text := 'RUN';
end;
if (MQTTClient1.Online) then
begin
Statusbar1.Panels.Items[1].Text := 'CONN';
// dumyTopic := '';
// dumyTopic := 'SMART-FARM/QST/MQTT_HUB/PUB/0000';
// pTopic := '';
// pTopic := dumyTopic;
// pMsg := '';
// S := '';
// S := formatdatetime('yyyymmddhhnnss',now());
// pMsg := format('{DATE_TIME=%s}', [S]);;
// MQTTClient1.Publish(pTopic, pMsg, aQos, false);
end else
begin
Statusbar1.Panels.Items[1].Text := 'DisCON';
end;
// for p:=1 to max_gw do NILM_ID_List
for i:=0 to NILM_ID_List.Count-1 do
begin
p := NILM_ID_List[i];
if (fNILM[p].rcvCount>0) and (fNILM[p].rcvCount <> fNILM[p].oldRcvCount) then
begin
fNILM[p].oldRcvCount := fNILM[p].RcvCount;
sql := '';
sql := 'UPDATE nilm_value SET '+
'pf_1='+floattostr(fNILM[p]._VALUE.PF[1] )+', '+
'pf_2='+floattostr(fNILM[p]._VALUE.PF[2] )+', '+
'pf_3='+floattostr(fNILM[p]._VALUE.PF[3] )+', '+
'Vrms_1='+floattostr(fNILM[p]._VALUE.Vrms[1] )+', '+
'Vrms_2='+floattostr(fNILM[p]._VALUE.Vrms[2] )+', '+
'Vrms_3='+floattostr(fNILM[p]._VALUE.Vrms[3] )+', '+
'Irms_1='+floattostr(fNILM[p]._VALUE.Irms[1] )+', '+
'Irms_2='+floattostr(fNILM[p]._VALUE.Irms[2] )+', '+
'Irms_3='+floattostr(fNILM[p]._VALUE.Irms[3] )+', '+
'Var_1='+floattostr(fNILM[p]._VALUE._Var[1] )+', '+
'Var_2='+floattostr(fNILM[p]._VALUE._Var[2] )+', '+
'Var_3='+floattostr(fNILM[p]._VALUE._Var[3] )+', '+
'Va_1='+floattostr(fNILM[p]._VALUE.Va[1] )+', '+
'Va_2='+floattostr(fNILM[p]._VALUE.Va[2] )+', '+
'Va_3='+floattostr(fNILM[p]._VALUE.Va[3] )+', '+
'Pwr_1='+floattostr(fNILM[p]._VALUE.Pwr[1] )+', '+
'Pwr_2='+floattostr(fNILM[p]._VALUE.Pwr[2] )+', '+
'Pwr_3='+floattostr(fNILM[p]._VALUE.Pwr[3] )+', '+
'gX='+floattostr(fNILM[p]._VALUE.Gyro[1])+', '+
'gY='+floattostr(fNILM[p]._VALUE.Gyro[2])+', '+
'gZ='+floattostr(fNILM[p]._VALUE.Gyro[3])+', '+
'aX='+floattostr(fNILM[p]._VALUE.Accel[1])+', '+
'aY='+floattostr(fNILM[p]._VALUE.Accel[2])+', '+
'aZ='+floattostr(fNILM[p]._VALUE.Accel[3])+', '+
'TempC='+floattostr(fNILM[p]._VALUE.TempC)+', '+
'lastUpdate=now()'+
' WHERE NilmID='+inttostr(p);
if fNILM[p].idxNo > 0 then insertSQL(sql);
sql := '';
sql := 'INSERT INTO '+format('nilm_%.5d',[fNILM[p].idxNo])+' VALUES(null, '+
''+inttostr(p)+', '+ // Nilm ID
''+floattostr(fNILM[p]._VALUE.PF[1] )+', 0, '+
''+floattostr(fNILM[p]._VALUE.Vrms[1] )+', '+
''+floattostr(fNILM[p]._VALUE.Irms[1] )+', '+
''+floattostr(fNILM[p]._VALUE._Var[1] )+', '+
''+floattostr(fNILM[p]._VALUE.Va[1] )+', '+
''+floattostr(fNILM[p]._VALUE.Pwr[1] )+', '+
''+floattostr(fNILM[p]._VALUE.PF[2] )+', 0, '+
''+floattostr(fNILM[p]._VALUE.Vrms[2] )+', '+
''+floattostr(fNILM[p]._VALUE.Irms[2] )+', '+
''+floattostr(fNILM[p]._VALUE._Var[2] )+', '+
''+floattostr(fNILM[p]._VALUE.Va[2] )+', '+
''+floattostr(fNILM[p]._VALUE.Pwr[2] )+', '+
''+floattostr(fNILM[p]._VALUE.PF[3] )+', 0, '+
''+floattostr(fNILM[p]._VALUE.Vrms[3] )+', '+
''+floattostr(fNILM[p]._VALUE.Irms[3] )+', '+
''+floattostr(fNILM[p]._VALUE._Var[3] )+', '+
''+floattostr(fNILM[p]._VALUE.Va[3] )+', '+
''+floattostr(fNILM[p]._VALUE.Pwr[3] )+', '+
''+floattostr(fNILM[p]._VALUE.Gyro[1])+', '+
''+floattostr(fNILM[p]._VALUE.Gyro[2])+', '+
''+floattostr(fNILM[p]._VALUE.Gyro[3])+', '+
''+floattostr(fNILM[p]._VALUE.Accel[1])+', '+
''+floattostr(fNILM[p]._VALUE.Accel[2])+', '+
''+floattostr(fNILM[p]._VALUE.Accel[3])+', '+
''+floattostr(fNILM[p]._VALUE.TempC)+', '+
'now())';
if fNILM[p].idxNo > 0 then insertSQL(sql);
// PrintLog(IntToStr(i)+' / '+inttostr(p),'SYS');
end;
end;
end;
procedure TfrmMain.ListBox1DblClick(Sender: TObject);
begin
msg_flaw_stop := not msg_flaw_stop;
end;
procedure TfrmMain.ProgramExit1Click(Sender: TObject);
begin
frmMain.Close;
end;
procedure TfrmMain.DebugMode1Click(Sender: TObject);
begin
DebugMode1.Checked := not DebugMode1.Checked;
debug_mode := DebugMode1.Checked;
debug_mode_count := 0;
end;
procedure TfrmMain.Config1Click(Sender: TObject);
begin
frmConfigMQTT.Show;
end;
procedure TfrmMain.Edit1Click(Sender: TObject);
begin
frmNILM.Show;
end;
procedure TfrmMain.N1Click(Sender: TObject);
begin
frmDevConfig.Show;
end;
function TfrmMain.DB_Connect:Boolean;
begin
FDPhysPgDriverLink1.VendorLib := '.\libpq-10.dll';
FDConnection1.Connected := False;
FDConnection1.Params.Clear;
FDConnection1.Params.DriverID := 'PG';
FDConnection1.Params.Database := Trim(dbSchema_PG);
FDConnection1.Params.UserName := Trim(dbUser_PG);
FDConnection1.Params.Password := Trim(dbPW_PG);
FDConnection1.Params.Add('Server=' + Trim(dbIP_PG));
FDConnection1.Params.Add('Port=' + Trim(IntToStr(dbPort_PG)));
FDConnection1.Params.Add('CharacterSet=UTF8');
try
FDConnection1.Connected := True;
Result := True;
// Memo1.Lines.Add('연결 성공');
// Memo1.Lines.Add('"Q1" 버튼을 누른 후 "쿼리" 버튼을 누르세요!!');
except
on E: Exception do begin
Result := False;
// Memo1.Lines.Add('연결 실패: ' + E.Message);
end;
end;
end;
function TfrmMain.DB_Close:Boolean;
begin
try
if FDConnection1.Connected then FDConnection1.Connected := False;
Result := True;
except
Result := False;
end;
end;
function TfrmMain.xAddSqlDoubleMark(velStr: String): string;
begin
Result := '';
Result := '"' + velStr + '"';
end;
function TfrmMain.xAddSqlMark(velStr: String): String;
begin
Result := '';
Result := '''' + velStr + '''';
end;
end.