unit uGtwyAgent; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, cxGraphics, cxControls, cxLookAndFeels, cxLookAndFeelPainters, cxStyles, cxCustomData, cxFilter, cxData, cxDataStorage, cxEdit, cxNavigator, dxDateRanges, dxScrollbarAnnotations, Vcl.StdCtrls, Vcl.ExtCtrls, cxGridLevel, cxGridCustomTableView, cxGridTableView, cxClasses, cxGridCustomView, cxGrid, Vcl.ComCtrls, IniFiles, System.JSON, uMQTTComps, System.StrUtils, uMQTT, global, System.Generics.Collections, 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, Data.DB, FireDAC.Comp.DataSet, FireDAC.Comp.Client, cxTextEdit, Calibration, System.Net.URLClient, System.Net.HttpClientComponent, System.Net.HttpClient, system.DateUtils, system.Hash, System.NetEncoding, AlarmLog, RegisterClasses_base, empmst, cxCurrencyEdit, MachineMst, FireDAC.Comp.ScriptCommands, FireDAC.Stan.Util, FireDAC.Comp.Script; type TSMSOptions = record // ToNumber: string; ToNumber: TStrings; FromNumber: string; Text: string; end; type TfGtwyAgent = class(TForm) PageControl1: TPageControl; TabSheet1: TTabSheet; TabSheet2: TTabSheet; TabSheet3: TTabSheet; cxGrid_GTWY: TcxGrid; cxGrid_GTWY_Tv: TcxGridTableView; cxGrid_GTWY_TvColumn0: TcxGridColumn; cxGrid_GTWY_TvColumn1: TcxGridColumn; cxGrid_GTWY_TvColumn2: TcxGridColumn; cxGrid_GTWY_TvColumn3: TcxGridColumn; cxGrid_GTWY_TvColumn4: TcxGridColumn; cxGrid_GTWY_TvColumn5: TcxGridColumn; cxGrid_GTWY_Lv: TcxGridLevel; Memo1: TMemo; Splitter1: TSplitter; Memo2: TMemo; GroupBox1: TGroupBox; Edit1: TEdit; Edit2: TEdit; Edit3: TEdit; Edit4: TEdit; Edit5: TEdit; GroupBox2: TGroupBox; Edit6: TEdit; Edit7: TEdit; Edit8: TEdit; Label1: TLabel; Label2: TLabel; Label3: TLabel; Label4: TLabel; Edit9: TEdit; Edit10: TEdit; Label5: TLabel; Label6: TLabel; Label7: TLabel; Label8: TLabel; Label9: TLabel; Label10: TLabel; Button3: TButton; Button4: TButton; MQTTClient1: TMQTTClient; Panel1: TPanel; CheckBox1: TCheckBox; CheckBox2: TCheckBox; FDConnection1: TFDConnection; FDQuery1: TFDQuery; FDPhysPgDriverLink1: TFDPhysPgDriverLink; FDGUIxWaitCursor1: TFDGUIxWaitCursor; TabSheet4: TTabSheet; GroupBox3: TGroupBox; Label11: TLabel; Label12: TLabel; Label13: TLabel; Label14: TLabel; cxGrid1: TcxGrid; cxGridTableView1: TcxGridTableView; cxGridColumn1: TcxGridColumn; cxGridColumn2: TcxGridColumn; cxGridColumn3: TcxGridColumn; cxGridColumn4: TcxGridColumn; cxGridLevel1: TcxGridLevel; Edit11: TEdit; Edit12: TEdit; Edit13: TEdit; Edit14: TEdit; Button1: TButton; Button2: TButton; cxGrid_GTWY_TvColumn6: TcxGridColumn; cxGrid_GTWY_TvColumn7: TcxGridColumn; cxGrid_GTWY_TvColumn8: TcxGridColumn; cxGrid_GTWY_TvColumn9: TcxGridColumn; cxGridColumn5: TcxGridColumn; cxGridColumn6: TcxGridColumn; cxGridColumn7: TcxGridColumn; cxGridColumn8: TcxGridColumn; Label19: TLabel; Edit18: TEdit; Label20: TLabel; Edit19: TEdit; Label21: TLabel; Label22: TLabel; Edit20: TEdit; Edit21: TEdit; cxGridColumn9: TcxGridColumn; cxGridColumn10: TcxGridColumn; cxGridColumn11: TcxGridColumn; Label15: TLabel; Edit15: TEdit; Label16: TLabel; Label17: TLabel; Edit16: TEdit; Edit17: TEdit; TrayIcon1: TTrayIcon; cxGridColumn12: TcxGridColumn; cxGridColumn13: TcxGridColumn; Edit22: TEdit; Edit23: TEdit; Label18: TLabel; Edit24: TEdit; cxGridColumn14: TcxGridColumn; TabSheet5: TTabSheet; cxGrid2: TcxGrid; cxGridTableView2: TcxGridTableView; cxGridLevel2: TcxGridLevel; Panel2: TPanel; GroupBox4: TGroupBox; Label23: TLabel; Label24: TLabel; Label25: TLabel; Edit25: TEdit; Edit26: TEdit; Edit27: TEdit; GroupBox5: TGroupBox; Label26: TLabel; Edit28: TEdit; DateTimePicker1: TDateTimePicker; Label28: TLabel; DateTimePicker2: TDateTimePicker; Label29: TLabel; Button7: TButton; GroupBox6: TGroupBox; Edit30: TEdit; Button9: TButton; Memo3: TMemo; Edit31: TEdit; Label30: TLabel; Edit32: TEdit; Memo4: TMemo; Memo5: TMemo; RadioButton1: TRadioButton; RadioButton2: TRadioButton; CheckBox3: TCheckBox; Edit33: TEdit; Label31: TLabel; Label32: TLabel; Label33: TLabel; RadioGroup1: TRadioGroup; cxGrid3: TcxGrid; cxGridTableView3: TcxGridTableView; cxGridLevel3: TcxGridLevel; cxGridTableView3Column1: TcxGridColumn; cxGridTableView3Column2: TcxGridColumn; cxGridTableView3Column3: TcxGridColumn; cxGridTableView3Column4: TcxGridColumn; cxGridTableView2Column1: TcxGridColumn; cxGridTableView2Column2: TcxGridColumn; cxGridTableView2Column3: TcxGridColumn; cxGridTableView2Column4: TcxGridColumn; cxGridTableView2Column5: TcxGridColumn; cxGridTableView2Column6: TcxGridColumn; cxGridTableView2Column7: TcxGridColumn; cxGridTableView2Column8: TcxGridColumn; cxGridTableView2Column9: TcxGridColumn; RadioGroup2: TRadioGroup; Button5: TButton; GroupBox7: TGroupBox; Label27: TLabel; Edit29: TEdit; Button8: TButton; cxGridColumn15: TcxGridColumn; Label35: TLabel; Edit34: TEdit; cxGridColumn16: TcxGridColumn; FDScript1: TFDScript; procedure Button4Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); procedure Button3Click(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 Button2Click(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure cxGridColumn2CustomDrawCell(Sender: TcxCustomGridTableView; ACanvas: TcxCanvas; AViewInfo: TcxGridTableDataCellViewInfo; var ADone: Boolean); procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); procedure TrayIcon1DblClick(Sender: TObject); procedure cxGridTableView1FocusedRecordChanged( Sender: TcxCustomGridTableView; APrevFocusedRecord, AFocusedRecord: TcxCustomGridRecord; ANewItemRecordFocusingChanged: Boolean); procedure Button9Click(Sender: TObject); procedure RadioButton2Click(Sender: TObject); procedure Button7Click(Sender: TObject); procedure Button5Click(Sender: TObject); procedure Button8Click(Sender: TObject); private inipath, deviceSettingpath : string; FsmsObj: TSMSOptions; procedure ini_Save; procedure ini_Load; procedure LoadTableViewFromFile(ATableView: TcxGridTableView; const AFileName: string); procedure SaveTableViewToFile(ATableView: TcxGridTableView; const AFileName: string); procedure PrintLog(msg, msgType: string); function SmoothAdcValue(gtwy,AI_NO,NewValue: Integer): Integer; function tempset_v2(gtwy,AI_NO,RawAdc:Integer):string; function TempCalibration(gtwy,AI_NO:Integer; temp: string): string; procedure AppEvtMinimize(Sender: TObject); procedure devRefresh; procedure insertSQL(sql: string); function xGenerateHMACSHA256(const Key, Data: string): string; function xSendSMS(const Options: TSMSOptions; const ServiceId, AccessKey, SecretKey: string): string; function qCreateGetUniqueString(clsName: string): string; procedure EmgAlarmlistrefresh; function AlarmSend(devName, temp_limit, temp_curr: string):Boolean; procedure CreateTabledevtemp_log(dev_idxno: integer); function Get_devtemp_idxNo: integer; function Alarm_use_CK: Boolean; { Private declarations } public { Public declarations } aQos: TMQTTQOSType; GTWY_ID_List : TList; GTWY_TOPIC_List : TList; procedure MQTTParsing(data : AnsiString; aTopic : String); function DB_Connect:Boolean; function DB_Close:Boolean; function MQTT_Connect:Boolean; end; const FILTER_SIZE = 10; // ÃÖ±Ù 10°³ Æò±Õ var fGtwyAgent: TfGtwyAgent; AdcIndexBuffer: array[0..3,0..3] of Integer; AdcBuffer: array[0..3,0..3,0..FILTER_SIZE-1] of Integer; AdcIndex: Integer = 0; Alarm_re: Integer; Alarm_use: Boolean; implementation uses uTempCalc_Custom, TemperatureConverter; const METHOD = 'POST'; CONTENT_TYPE = 'application/json; charset=utf-8'; COUNTRY_CODE = '82'; {$R *.dfm} function TfGtwyAgent.SmoothAdcValue(gtwy,AI_NO,NewValue: Integer): Integer; var i, Sum: Integer; AdcIndex : integer; begin AdcIndex := AdcIndexBuffer[gtwy,AI_NO]; AdcBuffer[gtwy,AI_NO,AdcIndex] := NewValue; AdcIndexBuffer[gtwy,AI_NO] := (AdcIndexBuffer[gtwy,AI_NO] + 1) mod FILTER_SIZE; // AdcIndex := (AdcIndex + 1) mod FILTER_SIZE; Sum := 0; for i := 0 to FILTER_SIZE-1 do Sum := Sum + AdcBuffer[gtwy,AI_NO,i]; Result := Round(Sum / FILTER_SIZE); end; function TfGtwyAgent.Alarm_use_CK:Boolean; var sql : string; begin Result := false; try if not FDConnection1.Connected then FDConnection1.Connected := True; if FDConnection1.Connected then begin sql := 'SELECT * FROM "MachineMst"'; sql := sql + ' WHERE "Name"=''ALARM'' '; sql := sql + ' AND "IsValid"=''t'' '; sql := sql + ' AND "LcStatus"=''ON'' ; '; FDQuery1.Close; FDQuery1.SQL.Clear; FDQuery1.SQL.Text := sql; FDQuery1.Open; if FDQuery1.RecordCount> 0 then begin result := True; end; end; except on e : exception do begin printlog('Database Connect Error :: '+e.Message, 'SYS'); end; end; end; procedure TfGtwyAgent.Button1Click(Sender: TObject); var row : integer; x, devtemp_idxno : Integer; sql : string; begin if FDConnection1.Connected then begin if (Trim(edit12.Text) <> '') and (Trim(edit14.Text) <> '') then begin FDQuery1.Close; FDQuery1.SQL.Clear; FDQuery1.SQL.Text := ' SELECT * FROM "devtemp_info" '+ ' WHERE "gatewayID"='+edit12.Text+ ' AND "AIPortNo"='+edit14.Text+ ' AND "isDeleted" = false '; FDQuery1.Open; end else begin ShowMessage('GTWY ID / AI Port No[0..3] Ç׸ñÀ» È®ÀÎÇϼ¼¿ä!'); exit; end; if FDQuery1.RecordCount> 0 then begin if MessageBox(handle, '¼öÁ¤ ÇϽðڽÀ´Ï±î?', '¼öÁ¤ ÇϽðڽÀ´Ï±î?', MB_OKCANCEL) = ID_OK then begin sql := ''; sql := 'UPDATE "devtemp_info" SET '+ '"deviceNAME" = '''+Edit11.Text+''', '+ '"gatewayID" = ' +Edit12.Text+', '+ '"mqttTOPIC" = '''+Edit13.Text+''', '+ '"AIPortNo" = ' +Edit14.Text+', '+ '"tempMAX" = ' +Edit18.Text+', '+ '"tempMIN" = ' +Edit34.Text+', '+ '"x_1" = ' +Edit19.Text+', '+ '"x_2" = ' +Edit20.Text+', '+ '"x_3" = ' +Edit21.Text+', '+ '"y_1" = ' +Edit15.Text+', '+ '"y_2" = ' +Edit16.Text+', '+ '"y_3" = ' +Edit17.Text+', '+ '"tempalarmMax" = ' +Edit24.Text+', '+ '"MachCode" = '''+Edit23.Text+''' '+ ' WHERE "gatewayID"='+edit12.Text+ ' AND "AIPortNo" ='+edit14.Text+ ' AND "isDeleted" = false ; '; insertSQL(sql); devRefresh; end; end else begin if MessageBox(handle, '»õ·Î¿î Àåºñ¸¦ Ãß°¡ÇϽðڽÀ´Ï±î?', 'Ãß°¡ÇϽðڽÀ´Ï±î?', MB_OKCANCEL) = ID_OK then begin sql := ''; sql := 'INSERT INTO devtemp_info VALUES(DEFAULT, '+ ''''+Edit11.Text+''', '+ ''+Edit12.Text+', '+ ''''+Edit13.Text+''', '+ ''+Edit14.Text+', '+ ''+Edit18.Text+', '+ ''+Edit19.Text+', '+ ''+Edit20.Text+', '+ ''+Edit21.Text+', '+ ''+Edit15.Text+', '+ ''+Edit16.Text+', '+ ''+Edit17.Text+', '+ '0, '+ 'NULL, '+ ''+Edit24.Text+', '+ 'now(), '+ 'false,'+ ''+Edit34.Text+ ') ; '; insertSQL(sql); devtemp_idxno := Get_devtemp_idxNo; if devtemp_idxno > 0 then CreateTabledevtemp_log(devtemp_idxno); devRefresh; end; end; end; end; function TfGtwyAgent.Get_devtemp_idxNo: integer; begin result := 0; try if not FDConnection1.Connected then FDConnection1.Connected := True; if FDConnection1.Connected then begin FDQuery1.Close; FDQuery1.SQL.Clear; FDQuery1.SQL.Text := ' SELECT * FROM "devtemp_info" '+ ' WHERE "gatewayID" = '+edit12.Text+ ' AND "AIPortNo" = '+edit14.Text+ ' AND "deviceNAME" = '''+edit11.Text+''''+ ' AND "isDeleted" = false '; FDQuery1.Open; if FDQuery1.RecordCount> 0 then begin result := FDQuery1.FieldByName('idxNo').AsInteger; end; end; except on e : exception do begin printlog('Database Connect Error :: '+e.Message, 'SYS'); end; end; end; procedure TfGtwyAgent.insertSQL(sql:string); begin try if not FDConnection1.Connected then FDConnection1.Connected := True; if FDConnection1.Connected then begin FDQuery1.ResourceOptions.DirectExecute := True; FDQuery1.Active := false; FDQuery1.SQL.Clear; FDQuery1.SQL.Add(sql); FDQuery1.ExecSQL; end; except on e : exception do begin printlog('[insertSQL()]Database Connect Error :: '+e.Message, 'SYS'); end; end; end; procedure TfGtwyAgent.Button2Click(Sender: TObject); var sql : string; begin if FDConnection1.Connected then begin if MessageBox(handle, '»èÁ¦ ÇϽðڽÀ´Ï±î?', '»èÁ¦ ÇϽðڽÀ´Ï±î?', MB_OKCANCEL) = ID_OK then begin sql := ''; { sql := ' DELETE FROM "devtemp_info" '+ ' WHERE "idxNo"='+edit22.Text+ ' AND "gatewayID"='+edit12.Text+ ' AND "AIPortNo" ='+edit14.Text; } sql := ' UPDATE "devtemp_info" SET '+ ' "isDeleted" = true, '+ ' "UpdateDT" = now()'+ ' WHERE "idxNo"='+edit22.Text+ ' AND "gatewayID"='+edit12.Text+ ' AND "AIPortNo" ='+edit14.Text+ ' ; '; insertSQL(sql); devRefresh; end; end; { with cxGridTableView1.DataController do begin if FocusedRecordIndex >= 0 then begin BeginUpdate; try DeleteSelection finally EndUpdate; end; end; end; } end; procedure TfGtwyAgent.Button3Click(Sender: TObject); begin Close; end; procedure TfGtwyAgent.Button4Click(Sender: TObject); begin ini_Save; end; procedure TfGtwyAgent.Button5Click(Sender: TObject); begin EmgAlarmlistrefresh; end; procedure TfGtwyAgent.CreateTabledevtemp_log(dev_idxno : integer); var sql : string; begin sql := ''; // PostgreSQL Å×ÀÌºí »ý¼º sql := 'CREATE TABLE IF NOT EXISTS "devtemp_'+format('%.5d',[dev_idxno])+'" ('+ '"aNo" SERIAL NOT NULL ,'+ '"MachCode" VARCHAR(20) ,'+ '"gatewayID" INTEGER ,'+ '"AIPortNo" INTEGER ,'+ '"TempC" REAL ,'+ '"lastUpdate" TIMESTAMP ,'+ '"RawAdc" INTEGER ,'+ '"SmoothedAdc" INTEGER ,'+ 'CONSTRAINT devtemp_'+format('%.5d',[dev_idxno])+'_pkey PRIMARY KEY ("aNo"));'; insertSQL(sql); end; procedure TfGtwyAgent.Button7Click(Sender: TObject); var alarmlog : Talarmlog; tmpList : TList; row, x : integer; ck_status : string; begin try tmpList := TList.Create; alarmlog := Talarmlog.Create(Self); ck_status:= ''; if RadioGroup2.ItemIndex > 0 then ck_status:= RadioGroup2.Items[RadioGroup2.ItemIndex]; tmpList := alarmlog.xGetObjsAlarmList(FDQuery1,ck_status,'','',FormatDateTime('yyyy-mm-dd',DateTimePicker1.Date),FormatDateTime('yyyy-mm-dd',DateTimePicker2.Date)); with cxGridTableView2.DataController do begin try BeginUpdate; RecordCount := 0; finally EndUpdate; end; end; for x := 0 to tmpList.Count-1 do begin alarmlog := tmpList.Items[x]; with cxGridTableView2.DataController do begin try BeginUpdate; row := AppendRecord; Values[row,cxGridTableView2Column1.Index] := alarmlog.MachType; Values[row,cxGridTableView2Column2.Index] := alarmlog.MachName; Values[row,cxGridTableView2Column3.Index] := alarmlog.CreateDate; Values[row,cxGridTableView2Column4.Index] := alarmlog.CreateTime; Values[row,cxGridTableView2Column5.Index] := alarmlog.AlarmStatus; Values[row,cxGridTableView2Column6.Index] := alarmlog.SendMsgDate; Values[row,cxGridTableView2Column7.Index] := alarmlog.SendMsgTime; Values[row,cxGridTableView2Column8.Index] := alarmlog.SendMsgEmp; Values[row,cxGridTableView2Column9.Index] := alarmlog.SendMsg; finally EndUpdate; end; end; end; finally tmpList.free; end; end; procedure TfGtwyAgent.Button8Click(Sender: TObject); var ini : TIniFile; begin Ini := TIniFile.Create(inipath); try if Trim(Edit29.Text) <> '' then Alarm_re := strtoint(Edit29.Text) else Alarm_re := 60; //Alarm_use := RadioButton5.Checked; Ini.WriteInteger('ALARM_RE','sec',Alarm_re); // Ini.WriteBool('ALARM','use',Alarm_use); finally Ini.Free; end; { try ini := TInifile.Create(inipath); with ini do begin WriteString('serverDB','IP', edit1.Text); WriteString('serverDB','PORT', edit2.Text); WriteString('serverDB','User', edit3.Text); WriteString('serverDB','Pass', edit4.Text); WriteString('serverDB','Schema',edit5.Text); WriteString('MQTTBroker','IP', edit6.Text); WriteString('MQTTBroker','PORT', edit7.Text); WriteString('MQTTBroker','ClientID',edit8.Text); WriteString('MQTTBroker','UserID', edit9.Text); WriteString('MQTTBroker','UserPASS',edit10.Text); end; finally ini.Free; end; } end; function TfGtwyAgent.qCreateGetUniqueString(clsName: string): string; var randomInt: Integer; tmStmp: TTimeStamp; dbName: string; begin //****************OBID±ÔÄ¢*****************// //Result := clsName(Ŭ·¡½º³×ÀÓ) + '-ŸÀÔ½ºÅÆÇÁ-' + '-6ÀÚ¸®·£´ý¼ö-' + 'µðºñ³×ÀÓ'; //****************OBID±ÔÄ¢*****************// Result := ''; tmStmp := DateTimeToTimeStamp(Now); randomInt := random(899998) + 100001; //100001 ~ 999999 dbName := 'neol_data'; Result := 'T' + clsName + '-' + IntToStr(tmStmp.Date) + IntToStr(tmStmp.Time) + '-' + IntToStr(randomInt) + '-' + dbName; end; procedure TfGtwyAgent.RadioButton2Click(Sender: TObject); begin if RadioButton1.Checked then begin Memo3.Clear; Memo3.Lines.Add('[³×¿Ã]'); Memo3.Lines.Add('%s'); Memo3.Lines.Add('ÀÓ°è°ª %s¡É / ÇöÀç %s¡É'); Memo3.Lines.Add('https://neol.co.kr'); end else begin Memo3.Clear; Memo3.Lines.Add('[³×¿Ã]'); Memo3.Lines.Add('[ %s ] ¿ÂµµÀÌ»ó °¨Áö'); Memo3.Lines.Add('ÀÓ°è°ª [ %s ¡É ] / ÇöÀç ¿Âµµ°ª [ %s ¡É ]'); Memo3.Lines.Add('https://neol.co.kr'); end; end; procedure TfGtwyAgent.EmgAlarmlistrefresh; var empmst : Tempmst; tmpList : TList; row, x : integer; begin try tmpList := TList.Create; empmst := Tempmst.Create(self); tmpList := empmst.xGetStrSqlEmpMstList(FDQuery1,'ÀçÁ÷','',''); with cxGridTableView3.DataController do begin try BeginUpdate; RecordCount := 0; finally EndUpdate; end; end; for x := 0 to tmpList.Count-1 do begin empmst := tmpList.Items[x]; if StrToBool(empmst.IsAlarm) then begin with cxGridTableView3.DataController do begin try BeginUpdate; row := AppendRecord; Values[row,cxGridTableView3Column1.Index] := StringReplace(empmst.EmpTelNum, '-', '', [rfReplaceAll]); Values[row,cxGridTableView3Column2.Index] := empmst.Name; Values[row,cxGridTableView3Column3.Index] := empmst.Position; Values[row,cxGridTableView3Column4.Index] := empmst.Role; finally EndUpdate; end; end; end; end; finally tmpList.free; end; end; function TfGtwyAgent.AlarmSend(devName,temp_limit,temp_curr:string):Boolean; var i: Integer; Response, pID, aKey, sKey: string; sql : string; ToNum : string; ToNumlist : TStringList; begin Result := False; EmgAlarmlistrefresh; Alarm_use := Alarm_use_CK; if RadioGroup1.ItemIndex = 1 then begin //TEST //ȸ»ç °èÁ¤..Å¥¼¾ÅØ.. pID := 'ncp:sms:kr:337071110685:qst'; aKey := 'qW8o6nlh4ORI7zpt0ai2'; sKey := 'Uqt8kJECZxvrBBYN1EMlmJfEGQuR4hStkvVuiSTS'; //Å¥¼¾ÅØ ¹ß½ÅÀÎÁõ ¹øÈ£.. FsmsObj.FromNumber := '07082802424'; end else begin // REAL //³×¿Ã..Access key, Secret key.. pID := Edit32.Text; aKey := Edit26.Text; sKey := Edit27.Text; //³×¿Ã ¹ß½ÅÀÎÁõ ¹øÈ£.. FsmsObj.FromNumber := '0336480037'; end; try try ToNumlist := TStringList.Create; with cxGridTableView3.DataController do begin for I := 0 to RecordCount-1 do begin ToNumlist.Add(Values[i,cxGridTableView3Column1.Index]); end; end; // ¼ö½ÅÀÚ¹øÈ£ FsmsObj.ToNumber := ToNumlist; if Alarm_use then begin FsmsObj.Text := Format(Memo3.Text, [devName,temp_curr,temp_limit]); end else begin FsmsObj.Text := '[¾Ë¶÷ ¹ÌÀü¼Û] '+Format(Memo3.Text, [devName,temp_curr,temp_limit]); end; if (Trim(FsmsObj.FromNumber) <> '') and (Trim(FsmsObj.Text) <> '') and (FsmsObj.ToNumber.Count > 0) then begin Memo4.Clear; Memo5.Clear; if Alarm_use then begin Response := xSendSMS(FsmsObj, pID, aKey, sKey); end else begin Response := '¾Ë¶÷ ¹ÌÀü¼Û'; end; ToNum := ''; for i := 0 to FsmsObj.ToNumber.Count-1 do begin Memo4.Lines.Add(FsmsObj.ToNumber.Strings[i]); if i = 0 then ToNum := FsmsObj.ToNumber.Strings[i] else ToNum := ToNum +' / '+ FsmsObj.ToNumber.Strings[i]; end; Memo4.Lines.Add(FsmsObj.FromNumber); Memo4.Lines.Add(FsmsObj.Text); Memo5.Lines.Add('ÀÀ´ä: ' + Response); sql := ''; sql := 'INSERT INTO "AlarmLog" VALUES( '+ ''''+''+''', '+ ''''+qCreateGetUniqueString('AlarmLog')+''', '+ ''''+'AlarmLog'+''', '+ ''''+FormatDateTime('yyyy-mm-dd',Now)+''', '+ ''''+FormatDateTime('hh:nn:ss.zzzzzz',Now)+''', '+ ''''+'GtwyAgent'+''', '+ ''''+'t'+''', '+ ''''+'Working'+''', '+ ''''+devName+''', '+ ''''+'Å»Áö'+''', '+ ''''+StringReplace(FsmsObj.Text, #$D#$A, '', [rfReplaceAll])+''', '+ ''''+FormatDateTime('yyyy-mm-dd',Now)+''', '+ ''''+FormatDateTime('hh:nn:ss.zzzzzz',Now)+''', '+ ''''+ToNum+''', '+ ''''+FormatDateTime('yyyy-mm-dd',Now)+''', '+ ''''+FormatDateTime('hh:nn:ss.zzzzzz',Now)+''', '; if StrToFloat(temp_curr) > StrToFloat(temp_limit) then begin sql := sql + ''''+'¿ÂµµÀÌ»ó'+''', '+ ''''+'°æ/Áß/½É°¢'+''', '+ ''''+'¹ß»ý'+''', '+ 'NULL '+ ');'; end else begin sql := sql + ''''+'¿ÂµµÁ¤»ó'+''', '+ ''''+'°æ/Áß/½É°¢'+''', '+ ''''+'¿Ï·á'+''', '+ 'NULL '+ ');'; end; insertSQL(sql); Result := True; end else begin if Trim(FsmsObj.FromNumber) = '' then begin Memo4.Lines.Add('¹ß½ÅÀÚ¹øÈ£ È®ÀÎÇÊ¿ä!'); end; if Trim(FsmsObj.Text) = '' then begin Memo4.Lines.Add('¸Þ¼¼Áö ³»¿ë È®ÀÎÇÊ¿ä!'); end; if FsmsObj.ToNumber.Count <= 0 then begin Memo4.Lines.Add('¼ö½ÅÀÚ¹øÈ£ È®ÀÎÇÊ¿ä!'); end; Result := False; end; except on e : exception do begin printlog('AlarmSend Error :: '+e.Message, 'SYS'); end; end; finally ToNumlist.Free; end; end; procedure TfGtwyAgent.Button9Click(Sender: TObject); begin AlarmSend(Edit30.Text,Edit31.Text,Edit33.Text); // Àåºñ¸í / ÀÓ°è°ª / ÇöÀç°ª end; function TfGtwyAgent.xGenerateHMACSHA256(const Key, Data: string): string; var HashBytes: TBytes; begin HashBytes := THashSHA2.GetHMACAsBytes(TEncoding.UTF8.GetBytes(Data), TEncoding.UTF8.GetBytes(Key), SHA256); Result := TNetEncoding.Base64.EncodeBytesToString(HashBytes); end; function TfGtwyAgent.xSendSMS(const Options: TSMSOptions; const ServiceId, AccessKey, SecretKey: string): string; var i: Integer; Client: TNetHTTPClient; Request: TStringStream; JsonObj, MsgObj: TJSONObject; JsonArray: TJSONArray; Response: IHTTPResponse; Timestamp: Int64; SignTarget, Signature, URL: string; begin Client := TNetHTTPClient.Create(nil); try Timestamp := DateTimeToUnix(TTimeZone.Local.ToUniversalTime(Now)) * 1000; //SignTarget := METHOD + ' ' + URL + #10 + IntToStr(Timestamp) + #10 + AccessKey; SignTarget := METHOD + ' ' + '/sms/v2/services/' + ServiceId + '/messages' + #10 + IntToStr(Timestamp) + #10 + AccessKey; //HMAC-SHA256 ¼­¸í »ý¼º (`THashSHA2` »ç¿ë) Signature := xGenerateHMACSHA256(SecretKey, SignTarget); URL := Format(Edit25.Text, [ServiceId]); JsonObj := TJSONObject.Create; try if RadioButton1.Checked then JsonObj.AddPair('type', 'SMS') else JsonObj.AddPair('type', 'MMS'); JsonObj.AddPair('contentType', 'COMM'); JsonObj.AddPair('countryCode', COUNTRY_CODE); JsonObj.AddPair('from', Options.FromNumber); JsonObj.AddPair('content', Options.Text); JsonArray := TJSONArray.Create; for i := 0 to Options.ToNumber.Count-1 do begin MsgObj := TJSONObject.Create; MsgObj.AddPair('to', Options.ToNumber.Strings[i]); MsgObj.AddPair('content', Options.Text); JsonArray.AddElement(MsgObj); end; JsonObj.AddPair('messages', JsonArray); Request := TStringStream.Create(JsonObj.ToJSON, TEncoding.UTF8); try Client.CustomHeaders['Content-Type'] := CONTENT_TYPE; Client.CustomHeaders['x-ncp-apigw-timestamp'] := IntToStr(Timestamp); Client.CustomHeaders['x-ncp-iam-access-key'] := AccessKey; Client.CustomHeaders['x-ncp-apigw-signature-v2'] := Signature; Response := Client.Post(Format(Edit25.Text, [ServiceId]), Request); Result := Response.ContentAsString; finally Request.Free; end; finally JsonObj.Free; end; finally Client.Free; end; end; procedure TfGtwyAgent.cxGridColumn2CustomDrawCell( Sender: TcxCustomGridTableView; ACanvas: TcxCanvas; AViewInfo: TcxGridTableDataCellViewInfo; var ADone: Boolean); begin ACanvas.Font.Color := $000000EA; end; procedure TfGtwyAgent.cxGridTableView1FocusedRecordChanged( Sender: TcxCustomGridTableView; APrevFocusedRecord, AFocusedRecord: TcxCustomGridRecord; ANewItemRecordFocusingChanged: Boolean); begin if Assigned(AFocusedRecord) then with cxGridTableView1.DataController do begin Edit11.Text := Values[AFocusedRecord.RecordIndex,cxGridColumn1.Index]; Edit12.Text := Values[AFocusedRecord.RecordIndex,cxGridColumn2.Index]; Edit13.Text := Values[AFocusedRecord.RecordIndex,cxGridColumn3.Index]; Edit14.Text := Values[AFocusedRecord.RecordIndex,cxGridColumn4.Index]; Edit18.Text := Values[AFocusedRecord.RecordIndex,cxGridColumn5.Index]; Edit34.Text := Values[AFocusedRecord.RecordIndex,cxGridColumn16.Index]; Edit19.Text := Values[AFocusedRecord.RecordIndex,cxGridColumn6.Index]; Edit20.Text := Values[AFocusedRecord.RecordIndex,cxGridColumn7.Index]; Edit21.Text := Values[AFocusedRecord.RecordIndex,cxGridColumn8.Index]; Edit15.Text := Values[AFocusedRecord.RecordIndex,cxGridColumn9.Index]; Edit16.Text := Values[AFocusedRecord.RecordIndex,cxGridColumn10.Index]; Edit17.Text := Values[AFocusedRecord.RecordIndex,cxGridColumn11.Index]; Edit24.Text := Values[AFocusedRecord.RecordIndex,cxGridColumn14.Index]; Edit22.Text := Values[AFocusedRecord.RecordIndex,cxGridColumn12.Index]; Edit23.Text := Values[AFocusedRecord.RecordIndex,cxGridColumn13.Index]; end; end; function TfGtwyAgent.TempCalibration(gtwy,AI_NO:Integer; temp: string): string; var x : Integer; Calib: TCalibration; xValues, yValues: TArray; inputTemperature, correctedTemperature: Double; use_ck : Boolean; begin // ¿Âµµ°è2(xValues)¿Í ¿Âµµ°è1(yValues)ÀÇ ÃøÁ¤°ª use_ck := false; with cxGridTableView1.DataController do begin for x := 0 to RecordCount-1 do begin if (Values[x,cxGridColumn2.Index]=gtwy) and (Values[x,cxGridColumn4.Index]=AI_NO) then begin xValues := [Values[x,cxGridColumn6.Index], Values[x,cxGridColumn7.Index], Values[x,cxGridColumn8.Index]]; // Àåºñ ¼ÂÆÃ ¿Âµµ yValues := [Values[x,cxGridColumn9.Index], Values[x,cxGridColumn10.Index], Values[x,cxGridColumn11.Index]]; // ÇöÀå ¿Âµµ use_ck := true; Break; end; end; end; try if use_ck then begin if (xValues[0]=0) or (xValues[0]=0) or (xValues[0]=0) or (yValues[0]=0) or (yValues[0]=0) or (yValues[0]=0) then begin result := temp; end else begin // TCalibration °´Ã¼ »ý¼º ¹× ÃʱâÈ­ Calib := TCalibration.Create(xValues, yValues); try // »ç¿ëÀÚ ÀÔ·Â ¹Þ±â inputTemperature := StrToFloatDef(temp,0); // º¸Á¤µÈ °ª °è»ê correctedTemperature := Calib.Calibrate(inputTemperature); // °á°ú Ãâ·Â result := Trim(Format('%14.1f',[correctedTemperature])); finally Calib.Free; end; end; end else begin result := temp; end; except on e : exception do begin printlog('TempCalibration_1 Error :: '+e.Message, 'SYS'); end; // on E: Exception do // Writeln(E.ClassName, ': ', E.Message); end; end; function TfGtwyAgent.tempset_v2(gtwy,AI_NO,RawAdc:Integer):string; var ActualTemperature: Double; SmoothedAdc: Integer; Temp_s, devTemp_machcode:string; TempMax, TempMin : integer; devTemp_idxNo : Integer; dev_use_ck : Boolean; Temp_Limit: Double; x, dev_use_row : integer; sql : string; begin SmoothedAdc := SmoothAdcValue(gtwy,AI_NO,RawAdc); // À̵¿Æò±Õ Àû¿ë if SmoothedAdc > 1 then begin // ¿¹¸¦ µé¾î, ADC °ªÀÌ 383 (°ÅÀÇ Áß°£°ª)À̶ó°í °¡Á¤ // CurrentADC := 383; dev_use_ck := false; Temp_Limit := 0; dev_use_row := -1; devTemp_machcode := ''; for x := 0 to cxGridTableView1.DataController.RecordCount-1 do begin if (cxGridTableView1.DataController.Values[x,cxGridColumn2.Index]=gtwy) and (cxGridTableView1.DataController.Values[x,cxGridColumn4.Index]=AI_NO) then begin TempMax := cxGridTableView1.DataController.Values[x,cxGridColumn5.Index]; TempMin := cxGridTableView1.DataController.Values[x,cxGridColumn16.Index]; Temp_Limit := cxGridTableView1.DataController.Values[x,cxGridColumn14.Index]; devTemp_machcode := cxGridTableView1.DataController.Values[x,cxGridColumn13.Index]; devTemp_idxNo := cxGridTableView1.DataController.Values[x,cxGridColumn12.Index]; dev_use_row := x; dev_use_ck := true; Break; end; end; ActualTemperature := ConvertADCToTemperature(SmoothedAdc,TempMin,TempMax); // Ãâ·Â: ¾à 849.67 µµ // ShowMessage(Format('ADC Value: %d -> Actual Temperature: %.2f', [SmoothedAdc, ActualTemperature])); // ½ÇÁ¦ ¼¾¼­ °ªÀº K1 ½á¸ÓÄ¿ÇÃÀ̹ǷΠ¼Ò¼öÁ¡ ÀÌÇÏ Ã³¸®´Â ÇöÀå ¿ä±¸»çÇ׿¡ µû¶ó ¹Ý¿Ã¸²ÇÏ¿© »ç¿ë °¡´É. Temp_s := TempCalibration(gtwy,AI_NO,Format('%.2f', [ActualTemperature])); try // ¾Ë¶÷ Àü¼Û // Alarm_use := Alarm_use_CK; // if Alarm_use and (Temp_Limit > 0) then begin if Temp_Limit > 0 then begin // ¾Ë¶÷À» »ç¿ëÁßÀ϶§¸¸ ¸Þ¼¼Áö Àü¼ÛÀ̾ú´Âµ¥ µðºñÀúÀåÀ» À§ÇØ º¯°æ if Temp_Limit < StrToFloat(Temp_s) then begin with cxGridTableView1.DataController do begin try BeginUpdate; if (Values[dev_use_row, cxGridColumn15.Index] = 0) or (Values[dev_use_row, cxGridColumn15.Index] >= Alarm_re) then begin // AlarmSend(Edit30.Text,Edit31.Text,Edit33.Text); // Àåºñ¸í / ÀÓ°è°ª / ÇöÀç°ª if AlarmSend(Values[dev_use_row, cxGridColumn1.Index]+' ¿Âµµ ÀÌ»ó',Format('%.2f', [Temp_Limit]),Temp_s) then begin Values[dev_use_row, cxGridColumn15.Index] := 1; end else begin Values[dev_use_row, cxGridColumn15.Index] := Values[dev_use_row, cxGridColumn15.Index] + 1; end; end else begin Values[dev_use_row, cxGridColumn15.Index] := Values[dev_use_row, cxGridColumn15.Index] + 1; end; finally EndUpdate; end; end; end else begin with cxGridTableView1.DataController do begin if Values[dev_use_row, cxGridColumn15.Index] > 0 then if AlarmSend(Values[dev_use_row, cxGridColumn1.Index]+' ¿Âµµ Á¤»ó',Format('%.2f', [Temp_Limit]),Temp_s) then begin Values[dev_use_row, cxGridColumn15.Index] := 0; end end; end; end; except on e : exception do begin printlog('Alarm Error :: '+e.Message, 'SYS'); end; end; try if dev_use_ck then begin if FDConnection1.Connected then begin sql := ''; sql := ' UPDATE "devtemp_info" SET '+ ' "tempCurr" = ''' +Temp_s+''', '+ ' "UpdateDT" = now()'+ ' WHERE "gatewayID"='+IntToStr(gtwy)+ ' AND "AIPortNo" ='+IntToStr(AI_NO)+ ' AND "isDeleted" = false ; '+ ' INSERT INTO "devtemp_'+format('%.5d',[devTemp_idxNo])+'" VALUES(DEFAULT, '+ ' '''+devTemp_machcode+''', '+ ' '+IntToStr(gtwy)+', '+ ' '+IntToStr(AI_NO)+', '+ ' '+Temp_s+', '+ ' now(), '+ ' '+IntToStr(RawAdc)+', '+ ' '+IntToStr(SmoothedAdc)+ ' ) ; '; insertSQL(sql); end; end; Except on e : exception do begin printlog('Database Update Error :: '+e.Message, 'SYS'); end; end; Result := IntToStr(SmoothedAdc)+'/'+Temp_s; end else begin Result := 'OFF'; end; end; procedure TfGtwyAgent.TrayIcon1DblClick(Sender: TObject); begin TrayIcon1.Visible := False; Show; WindowState := wsNormal; Application.BringToFront; end; procedure TfGtwyAgent.FormClose(Sender: TObject; var Action: TCloseAction); begin CheckBox1.Checked := False; CheckBox2.Checked := False; try MQTTClient1.Activate(false); except end; try if FDConnection1.Connected then FDConnection1.Close; except end; try GTWY_ID_List.Free; GTWY_TOPIC_List.Free; except end; end; procedure TfGtwyAgent.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin case MessageBox(handle, '"¿¹(Y)"¸¦ Ŭ¸¯Çϸé, MQTT Client for GTWY Agent°¡ Æ®·¹ÀÌ·Î ÃÖ¼ÒÈ­ µË´Ï´Ù.'+#$0D#$0A#$0D#$0A+'"¾Æ´Ï¿À(N)"¸¦ Ŭ¸¯Çϸé ÇÁ·Î±×·¥ÀÌ Á¾·áµË´Ï´Ù. ', 'MQTT Client for GTWY Agent :: Æ®·¹ÀÌ·Î ÃÖ¼ÒÈ­ ÇÒ±î¿ä?', MB_YESNOCANCEL) of ID_YES : begin CanClose := false; TrayIcon1.BalloonTitle := 'MQTT Client for GTWY Agent È­¸éÀ» ´Ù½Ã º¸·Á¸é...'; TrayIcon1.BalloonHint := 'Æ®·¹ÀÌ ¾ÆÀÌÄÜÀ» ´õºíŬ¸¯Çϼ¼¿ä.'; //TrayIcon1.BalloonFlags := bfInfo; AppEvtMinimize(self); end; ID_CANCEL : begin CanClose := false; end; end;//case.. end; procedure TfGtwyAgent.AppEvtMinimize(Sender: TObject); begin Hide; WindowState := wsMinimized; TrayIcon1.Visible := True; TrayIcon1.Animate := True; TrayIcon1.ShowBalloonHint; end; procedure TfGtwyAgent.FormCreate(Sender: TObject); var x : Integer; begin DateTimePicker1.DateTime := Now; DateTimePicker2.DateTime := Now; inipath := ExtractFilePath(Application.ExeName)+'GtwyAgent.ini'; deviceSettingpath := ExtractFilePath(Application.ExeName)+'GtwyAgent_device.dat'; ini_Load; FillChar(AdcBuffer, SizeOf(AdcBuffer), 0); FillChar(AdcIndexBuffer, SizeOf(AdcIndexBuffer), 0); GTWY_ID_List := TList.Create; GTWY_TOPIC_List := TList.Create; GTWY_TOPIC_List.Clear; try if DB_Connect then printlog('DB Connected', 'SYS') else printlog('DB Connect Fail', 'SYS'); except on e : exception do begin printlog('DB Connect Error :: '+e.Message, 'SYS'); end; end; try if MQTT_Connect then printlog('MQTT Connected', 'SYS') else printlog('MQTT Connect Fail', 'SYS'); except on e : exception do begin printlog('MQTT Connect Error :: '+e.Message, 'SYS'); end; end; devRefresh; if cxGridTableView1.DataController.RecordCount > 0 then begin for x := 0 to cxGridTableView1.DataController.RecordCount-1 do begin GTWY_TOPIC_List.Add(cxGridTableView1.DataController.Values[x,cxGridColumn3.Index]); end; end; end; procedure TfGtwyAgent.devRefresh; var row : integer; begin with cxGridTableView1.DataController do begin try BeginUpdate; RecordCount := 0; finally EndUpdate; end; end; if FDConnection1.Connected then begin FDQuery1.Close; FDQuery1.SQL.Clear; FDQuery1.SQL.Text := 'SELECT * FROM "devtemp_info" WHERE "isDeleted" = false '; FDQuery1.Open; if FDQuery1.RecordCount> 0 then begin FDQuery1.First; while not FDQuery1.Eof do begin with cxGridTableView1.DataController do begin try BeginUpdate; row := AppendRecord; Values[row,cxGridColumn1.Index] := FDQuery1.FieldByName('deviceNAME').asString; Values[row,cxGridColumn2.Index] := FDQuery1.FieldByName('gatewayID').asString; Values[row,cxGridColumn3.Index] := FDQuery1.FieldByName('mqttTOPIC').asString; Values[row,cxGridColumn4.Index] := FDQuery1.FieldByName('AIPortNo').asString; Values[row,cxGridColumn5.Index] := StrToIntDef(FDQuery1.FieldByName('tempMAX').asString, 0); Values[row,cxGridColumn16.Index] := StrToIntDef(FDQuery1.FieldByName('tempMIN').asString, 0); Values[row,cxGridColumn6.Index] := StrToIntDef(FDQuery1.FieldByName('x_1').asString, 0); Values[row,cxGridColumn7.Index] := StrToIntDef(FDQuery1.FieldByName('x_2').asString, 0); Values[row,cxGridColumn8.Index] := StrToIntDef(FDQuery1.FieldByName('x_3').asString, 0); Values[row,cxGridColumn9.Index] := StrToIntDef(FDQuery1.FieldByName('y_1').asString, 0); Values[row,cxGridColumn10.Index] := StrToIntDef(FDQuery1.FieldByName('y_2').asString, 0); Values[row,cxGridColumn11.Index] := StrToIntDef(FDQuery1.FieldByName('y_3').asString, 0); Values[row,cxGridColumn14.Index] := StrToIntDef(FDQuery1.FieldByName('tempalarmMax').asString, 0); Values[row,cxGridColumn12.Index] := FDQuery1.FieldByName('idxNo').asString; Values[row,cxGridColumn13.Index] := FDQuery1.FieldByName('MachCode').asString; Values[row,cxGridColumn15.Index] := 0; finally EndUpdate; end; end; FDQuery1.Next; end; end; end; end; procedure TfGtwyAgent.ini_Save; var ini : TIniFile; begin try inipath := ExtractFilePath(Application.ExeName)+'GtwyAgent.ini'; ini := TInifile.Create(inipath); with ini do begin WriteString('serverDB','IP', edit1.Text); WriteString('serverDB','PORT', edit2.Text); WriteString('serverDB','User', edit3.Text); WriteString('serverDB','Pass', edit4.Text); WriteString('serverDB','Schema',edit5.Text); WriteString('MQTTBroker','IP', edit6.Text); WriteString('MQTTBroker','PORT', edit7.Text); WriteString('MQTTBroker','ClientID',edit8.Text); WriteString('MQTTBroker','UserID', edit9.Text); WriteString('MQTTBroker','UserPASS',edit10.Text); end; finally ini.Free; end; end; procedure TfGtwyAgent.ini_Load; var ini : TIniFile; begin if FileExists(inipath) then begin ini := TInifile.Create(inipath); with ini do begin edit1.Text := ReadString('serverDB','IP',''); edit2.Text := ReadString('serverDB','PORT',''); edit3.Text := ReadString('serverDB','User',''); edit4.Text := ReadString('serverDB','Pass',''); edit5.Text := ReadString('serverDB','Schema',''); edit6.Text := ReadString('MQTTBroker','IP',''); edit7.Text := ReadString('MQTTBroker','PORT',''); edit8.Text := ReadString('MQTTBroker','ClientID',''); edit9.Text := ReadString('MQTTBroker','UserID',''); edit10.Text := ReadString('MQTTBroker','UserPASS',''); Alarm_re := Ini.ReadInteger('ALARM_RE','sec',60); Edit29.Text := IntToStr(Alarm_re); end; ini.Free; end; // LoadTableViewFromFile(cxGridTableView1,deviceSettingpath); end; procedure TfGtwyAgent.SaveTableViewToFile(ATableView: TcxGridTableView; const AFileName: string); var JSONArray: TJSONArray; RowObj: TJSONObject; Row, Col: Integer; JSONText: TStringList; ValueStr: string; begin JSONArray := TJSONArray.Create; try // ¸ðµç Row ¹Ýº¹ for Row := 0 to ATableView.DataController.RecordCount - 1 do begin RowObj := TJSONObject.Create; for Col := 0 to ATableView.ColumnCount - 1 do begin ValueStr := VarToStr(ATableView.DataController.Values[Row, ATableView.Columns[Col].Index]); RowObj.AddPair(ATableView.Columns[Col].Name, ValueStr); end; JSONArray.AddElement(RowObj); end; JSONText := TStringList.Create; try JSONText.Text := JSONArray.Format(2); // º¸±â ÁÁ°Ô µé¿©¾²±â JSONText.SaveToFile(AFileName, TEncoding.UTF8); finally JSONText.Free; end; finally JSONArray.Free; end; end; procedure TfGtwyAgent.LoadTableViewFromFile(ATableView: TcxGridTableView; const AFileName: string); var JSONArray: TJSONArray; RowObj: TJSONObject; Row, Col: Integer; JSONStr: TStringList; JSONVal: TJSONValue; ColName, ColValue: string; ValueObj: TJSONValue; begin if not FileExists(AFileName) then Exit; JSONStr := TStringList.Create; try JSONStr.LoadFromFile(AFileName, TEncoding.UTF8); JSONVal := TJSONObject.ParseJSONValue(JSONStr.Text); try if not (JSONVal is TJSONArray) then Exit; JSONArray := TJSONArray(JSONVal); ATableView.DataController.RecordCount := JSONArray.Count; for Row := 0 to JSONArray.Count - 1 do begin RowObj := JSONArray.Items[Row] as TJSONObject; for Col := 0 to ATableView.ColumnCount - 1 do begin ColName := ATableView.Columns[Col].Name; ValueObj := RowObj.GetValue(ColName); if Assigned(ValueObj) then begin ColValue := ValueObj.Value; ATableView.DataController.Values[Row, ATableView.Columns[Col].Index] := ColValue; end; end; end; finally JSONVal.Free; end; finally JSONStr.Free; end; end; procedure TfGtwyAgent.MQTTClient1ClientID(Sender: TObject; var aClientID: UTF8String); begin PrintLog('ClientID :: ' + aClientID, 'SYS'); end; procedure TfGtwyAgent.MQTTClient1EnableChange(Sender: TObject); begin if TMQTTClient(Sender).Enabled then printlog('Client is enabled.', 'SYS') else printlog('Client is disabled.', 'SYS'); end; procedure TfGtwyAgent.MQTTClient1Failure(Sender: TObject; aReason: Integer; var CloseClient: Boolean); begin printlog('---- Failure Reported ' + FailureNames(aReason), 'SYS'); end; procedure TfGtwyAgent.MQTTClient1Mon(Sender: TObject; aStr: string); begin printlog(aStr, 'SYS'); end; procedure TfGtwyAgent.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, 'mqtt'); 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 TfGtwyAgent.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 TfGtwyAgent.MQTTClient1Online(Sender: TObject); var s: TStringList; x : Integer; begin printlog('Client is online.', 'SYS'); s := TStringList.Create; if GTWY_TOPIC_List.Count > 0 then begin for x := 0 to GTWY_TOPIC_List.Count-1 do s.AddObject(GTWY_TOPIC_List[x], TObject(aQos)); end; MQTTClient1.Subscribe(s); s.Free; end; procedure TfGtwyAgent.PrintLog(msg, msgType : string); var f : TextFile; log: TStringList; i : integer; logfile, buf : string; begin if msgType = 'mqtt' then begin if CheckBox1.Checked then begin while Memo2.Lines.Count > 100 do begin Memo2.Lines.Delete(0); end; Memo2.Lines.Add(FormatDateTime('yyyy-mm-dd hh:nn:ss :: ',now)+msg); end; end else begin if CheckBox1.Checked or (msgType = 'SYS') then begin while Memo1.Lines.Count > 100 do begin Memo1.Lines.Delete(0); end; Memo1.Lines.Add(FormatDateTime('yyyy-mm-dd hh:nn:ss :: ',now)+msg); end; end; if CheckBox2.Checked or (msgType = 'SYS') then begin logfile := ''; logfile := ExtractFilePath(Application.ExeName)+'log\GTWYAgent_'+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 TfGtwyAgent.MQTTParsing(data : AnsiString; aTopic : String); var tempTopic_list, tempAI_list : TStringList; AI_01, AI_02, AI_03, AI_04 : Single; gtwyID, x : integer; tempAI : string; grid_rowck : integer; ck1,ck2 : string; str_list : TStringList; JSONObject: TJSONObject; begin try if Trim(data) <> '' then begin // InsertData(aTopic, data); try tempTopic_list := TStringList.Create; tempAI_list := TStringList.create; // JSON ¹®ÀÚ¿­À» TJSONObject·Î ÆÄ½Ì JSONObject := TJSONObject.ParseJSONValue(data) as TJSONObject; Strsplit('/',aTopic, tempTopic_list); if tempTopic_list.Count>3 then begin gtwyID := StrToIntDef(tempTopic_list.Strings[ tempTopic_list.Count-1 ], 0); grid_rowck := GTWY_ID_List.IndexOf(gtwyID); if (gtwyID > 0) and (gtwyID <= 4) then begin if JSONObject.GetValue('AI') <> nil then begin tempAI := JSONObject.GetValue('AI').Value; Strsplit('|',tempAI, tempAI_list); grid_rowck := -1; // if PageControl1.TabIndex = 0 then with cxGrid_GTWY_Tv.DataController do begin for x := 0 to RecordCount-1 do begin if Values[x,cxGrid_GTWY_TvColumn0.Index] = gtwyID then grid_rowck := x; end; if grid_rowck < 0 then begin grid_rowck := AppendRecord; end; try BeginUpdate; Values[grid_rowck,cxGrid_GTWY_TvColumn0.Index] := gtwyID; Values[grid_rowck,cxGrid_GTWY_TvColumn1.Index] := FormatDateTime('yymmdd hhnnss',Now); str_list := TStringList.Create; str_list.Delimiter := '/'; str_list.DelimitedText := tempset_v2(gtwyID,0,StrToIntDef(tempAI_list.Strings[0],0)); if str_list.DelimitedText <> 'OFF' then begin Values[grid_rowck,cxGrid_GTWY_TvColumn2.Index] := str_list.Strings[0]; Values[grid_rowck,cxGrid_GTWY_TvColumn6.Index] := str_list.Strings[1]; end else begin Values[grid_rowck,cxGrid_GTWY_TvColumn2.Index] := 'OFF'; Values[grid_rowck,cxGrid_GTWY_TvColumn6.Index] := 'OFF'; end; str_list.DelimitedText := tempset_v2(gtwyID,1,StrToIntDef(tempAI_list.Strings[1],0)); if str_list.DelimitedText <> 'OFF' then begin Values[grid_rowck,cxGrid_GTWY_TvColumn3.Index] := str_list.Strings[0]; Values[grid_rowck,cxGrid_GTWY_TvColumn7.Index] := str_list.Strings[1]; end else begin Values[grid_rowck,cxGrid_GTWY_TvColumn3.Index] := 'OFF'; Values[grid_rowck,cxGrid_GTWY_TvColumn7.Index] := 'OFF'; end; str_list.DelimitedText := tempset_v2(gtwyID,2,StrToIntDef(tempAI_list.Strings[2],0)); if str_list.DelimitedText <> 'OFF' then begin Values[grid_rowck,cxGrid_GTWY_TvColumn4.Index] := str_list.Strings[0]; Values[grid_rowck,cxGrid_GTWY_TvColumn8.Index] := str_list.Strings[1]; end else begin Values[grid_rowck,cxGrid_GTWY_TvColumn4.Index] := 'OFF'; Values[grid_rowck,cxGrid_GTWY_TvColumn8.Index] := 'OFF'; end; str_list.DelimitedText := tempset_v2(gtwyID,3,StrToIntDef(tempAI_list.Strings[3],0)); if str_list.DelimitedText <> 'OFF' then begin Values[grid_rowck,cxGrid_GTWY_TvColumn5.Index] := str_list.Strings[0]; Values[grid_rowck,cxGrid_GTWY_TvColumn9.Index] := str_list.Strings[1]; end else begin Values[grid_rowck,cxGrid_GTWY_TvColumn5.Index] := 'OFF'; Values[grid_rowck,cxGrid_GTWY_TvColumn9.Index] := 'OFF'; end; { Values[grid_rowck,cxGrid_GTWY_TvColumn2.Index] := tempAI_list.Strings[0]; Values[grid_rowck,cxGrid_GTWY_TvColumn3.Index] := tempAI_list.Strings[1]; Values[grid_rowck,cxGrid_GTWY_TvColumn4.Index] := tempAI_list.Strings[2]; Values[grid_rowck,cxGrid_GTWY_TvColumn5.Index] := tempAI_list.Strings[3]; Values[grid_rowck,cxGrid_GTWY_TvColumn6.Index] := tempset_v1(gtwyID,0,StrToIntDef(tempAI_list.Strings[0],0)); Values[grid_rowck,cxGrid_GTWY_TvColumn7.Index] := tempset_v1(gtwyID,1,StrToIntDef(tempAI_list.Strings[1],0)); Values[grid_rowck,cxGrid_GTWY_TvColumn8.Index] := tempset_v1(gtwyID,2,StrToIntDef(tempAI_list.Strings[2],0)); Values[grid_rowck,cxGrid_GTWY_TvColumn9.Index] := tempset_v1(gtwyID,3,StrToIntDef(tempAI_list.Strings[3],0)); } { 2025-11-14 °ªÃßÃâÀ» À§ÇÑ Àӽà º¯°æ if StrToIntDef(tempAI_list.Strings[0],0) > 3 then Values[grid_rowck,cxGrid_GTWY_TvColumn6.Index] := tempset(gtwyID,0,StrToInt(tempAI_list.Strings[0])) else Values[grid_rowck,cxGrid_GTWY_TvColumn6.Index] := 'OFF'; if StrToIntDef(tempAI_list.Strings[1],0) > 3 then Values[grid_rowck,cxGrid_GTWY_TvColumn7.Index] := tempset(gtwyID,1,StrToInt(tempAI_list.Strings[1])) else Values[grid_rowck,cxGrid_GTWY_TvColumn7.Index] := 'OFF'; if StrToIntDef(tempAI_list.Strings[2],0) > 3 then Values[grid_rowck,cxGrid_GTWY_TvColumn8.Index] := tempset(gtwyID,2,StrToInt(tempAI_list.Strings[2])) else Values[grid_rowck,cxGrid_GTWY_TvColumn8.Index] := 'OFF'; if StrToIntDef(tempAI_list.Strings[3],0) > 3 then Values[grid_rowck,cxGrid_GTWY_TvColumn9.Index] := tempset(gtwyID,3,StrToInt(tempAI_list.Strings[3])) else Values[grid_rowck,cxGrid_GTWY_TvColumn9.Index] := 'OFF'; } finally EndUpdate; end; end; end; end; end; finally tempTopic_list.Free; tempAI_list.Free; JSONObject.Free; end; end; except on e : exception do begin printlog('MQTTParsing Error :: '+e.Message, 'SYS'); end; end; end; function TfGtwyAgent.DB_Connect:Boolean; begin try FDPhysPgDriverLink1.VendorLib := '.\libpq-10.dll'; FDConnection1.Connected := False; FDConnection1.Params.Clear; FDConnection1.Params.DriverID := 'PG'; FDConnection1.Params.Database := Trim(Edit5.Text); FDConnection1.Params.UserName := Trim(Edit3.Text); FDConnection1.Params.Password := Trim(Edit4.Text); FDConnection1.Params.Add('Server=' + Trim(Edit1.Text)); FDConnection1.Params.Add('Port=' + Trim(Edit2.Text)); FDConnection1.Params.Add('CharacterSet=UTF8'); FDConnection1.Connected := True; Result := True; // Memo1.Lines.Add('¿¬°á ¼º°ø'); // Memo1.Lines.Add('"Q1" ¹öưÀ» ´©¸¥ ÈÄ "Äõ¸®" ¹öưÀ» ´©¸£¼¼¿ä!!'); except on e: exception do begin Result := False; Memo1.Lines.Add('DB ¿¬°á ½ÇÆÐ: ' + e.Message); end; end; end; function TfGtwyAgent.DB_Close:Boolean; begin try if FDConnection1.Connected then FDConnection1.Connected := False; Result := True; except Result := False; end; end; function TfGtwyAgent.MQTT_Connect: Boolean; begin try Result := False; MQTTClient1.Activate(false); Sleep(300); randomize(); MQTTClient1.ClientID := Trim(Edit8.Text)+'_'+inttostr(random(999999)); MQTTClient1.Host := Trim(Edit6.Text); MQTTClient1.Port := StrToInt(Trim(Edit7.Text)); MQTTClient1.Username := Trim(Edit9.Text); MQTTClient1.Password := Trim(Edit10.Text); MQTTClient1.Activate(true); Result := True; except on E: Exception do begin Result := False; Memo1.Lines.Add('MQTT ¿¬°á ½ÇÆÐ: ' + E.Message); end; end; end; end.