瀏覽代碼

2020/01/16 Jessica

Actions:
1.DLL 替換成5ea1b39 的檔案
2.測試工具 預約時間可自行設定 & Fix Upload功能
3.紀錄Message解析失敗的訊息
Jessica.Tseng 5 年之前
父節點
當前提交
f91cffd722

二進制
EVCB_OCPP.WSServer/DLL/EVCB_OCPP.Domain.dll


二進制
EVCB_OCPP.WSServer/DLL/EVCB_OCPP.Packet.dll


+ 37 - 23
EVCB_OCPP.WSServer/Message/BasicMessageHandler.cs

@@ -76,16 +76,16 @@ namespace EVCB_OCPP.WSServer.Message
                         case TYPENUMBER_CALL:
                             {
                                 //只有CallMessage 才有在RawData有Action
-                                IRequest request = UnPackPayloadbyCall(msg.Action, msg.Payload.ToString());
+                                BasicMessageResult baseResult = UnPackPayloadbyCall(msg.Action, msg.Payload.ToString());
                                 Actions action = Actions.None;
                                 Enum.TryParse<Actions>(msg.Action, out action);
                                 result.Action = msg.Action;
-                                if (request != null)
+                                if (baseResult.Request != null)
                                 {
-                                    if (request.Validate())
+                                    if (baseResult.Request.Validate())
                                     {
                                         result.Id = TYPENUMBER_CALL;
-                                        result.Message = request;
+                                        result.Message = baseResult.Request;
 
                                     }
                                     else
@@ -93,9 +93,10 @@ namespace EVCB_OCPP.WSServer.Message
                                         string replyMsg = GenerateCallError(msg.Id, OCPPErrorCodes.OccurenceConstraintViolation.ToString(),
                                              OCPPErrorDescription.OccurenceConstraintViolation);
                                         result.Id = TYPENUMBER_CALL;
-                                        result.Message = request;
+                                        result.Message = baseResult.Request;
                                         result.Success = false;
                                         result.CallErrorMsg = replyMsg;
+                                        result.Exception = new Exception("Validate Failed");
 
                                     }
                                 }
@@ -103,25 +104,26 @@ namespace EVCB_OCPP.WSServer.Message
                                 {
                                     string replyMsg = GenerateCallError(msg.Id, OCPPErrorCodes.OccurenceConstraintViolation, OCPPErrorDescription.OccurenceConstraintViolation);
                                     result.Id = TYPENUMBER_CALL;
-                                    result.Message = request;
+                                    result.Message = baseResult.Request;
                                     result.Success = false;
                                     result.CallErrorMsg = replyMsg;
+                                    result.Exception = baseResult.Exception;
                                 }
 
                             }
                             break;
                         case TYPENUMBER_CALLRESULT:
                             {
-                                IConfirmation confirmation = UnPackPayloadbyCallResult(client.queue, msg.Id, msg.Payload.ToString());
+                                BasicMessageResult baseResult = UnPackPayloadbyCallResult(client.queue, msg.Id, msg.Payload.ToString());
 
-                                if (confirmation != null)
+                                if (baseResult.Confirmation != null)
                                 {
 
-                                    if (confirmation.Validate())
+                                    if (baseResult.Confirmation.Validate())
                                     {
                                         result.Id = TYPENUMBER_CALLRESULT;
-                                        result.Message = confirmation;
-                                        result.Action = confirmation.GetRequest().Action;
+                                        result.Message = baseResult.Confirmation;
+                                        result.Action = baseResult.Confirmation.GetRequest().Action;
                                         //return data
                                     }
                                     else
@@ -129,9 +131,10 @@ namespace EVCB_OCPP.WSServer.Message
                                         string replyMsg = GenerateCallError(msg.Id, OCPPErrorCodes.OccurenceConstraintViolation.ToString(),
                                       OCPPErrorDescription.OccurenceConstraintViolation);
                                         result.Id = TYPENUMBER_CALLRESULT;
-                                        result.Message = confirmation;
+                                        result.Message = baseResult.Confirmation;
                                         result.Success = false;
                                         result.CallErrorMsg = replyMsg;
+                                        result.Exception = new Exception("Validate Failed");
                                     }
                                 }
                                 else
@@ -139,9 +142,10 @@ namespace EVCB_OCPP.WSServer.Message
                                     string replyMsg = GenerateCallError(msg.Id, OCPPErrorCodes.OccurenceConstraintViolation.ToString(),
                                    OCPPErrorDescription.OccurenceConstraintViolation);
                                     result.Id = TYPENUMBER_CALLRESULT;
-                                    result.Message = confirmation;
+                                    result.Message = baseResult.Confirmation;
                                     result.Success = false;
                                     result.CallErrorMsg = replyMsg;
+                                    result.Exception = baseResult.Exception;
                                 }
 
                             }
@@ -236,8 +240,9 @@ namespace EVCB_OCPP.WSServer.Message
         }
 
 
-        private IRequest UnPackPayloadbyCall(string action, string payload)
+        private BasicMessageResult UnPackPayloadbyCall(string action, string payload)
         {
+            BasicMessageResult result = new BasicMessageResult();
             try
             {
                 Feature feature = null;
@@ -254,19 +259,24 @@ namespace EVCB_OCPP.WSServer.Message
                     }
                 }
 
-                return JsonConvert.DeserializeObject(payload, feature.GetRequestType()) as IRequest;
+                result.Request =  JsonConvert.DeserializeObject(payload, feature.GetRequestType()) as IRequest;
+               
             }
             catch (Exception ex)
             {
+                result.Exception = ex;
                 logger.Error(string.Format("UnPackPayloadbyCall Ex: {0}", ex.ToString()), "UnPack");
-                return null;
+               
             }
+
+            return result;
         }
 
-        private IConfirmation UnPackPayloadbyCallResult(Queue requestQueue, string uniqueId, string payload)
+        private BasicMessageResult UnPackPayloadbyCallResult(Queue requestQueue, string uniqueId, string payload)
         {
+            BasicMessageResult result = new BasicMessageResult();
             try
-            {
+            {              
                 IRequest request = requestQueue.RestoreRequest(uniqueId);
                 Feature feature = null;
                 foreach (var profile in profiles)
@@ -281,21 +291,25 @@ namespace EVCB_OCPP.WSServer.Message
                         break;
                     }
                 }
+
                 IConfirmation confrim = JsonConvert.DeserializeObject(payload, feature.GetConfirmationType()) as IConfirmation;
                 confrim.SetRequest(request);
-                return confrim;
+                result.Confirmation = confrim;
+               
             }
             catch (Exception ex)
-            {
+            {                
+                result.Exception = ex;
                 logger.Error(string.Format("UnPackPayloadbyCallResult Data:[{0},{1}] Ex: {2}", uniqueId, payload, ex.ToString()), "UnPack");
-                return null;
+              
             }
+            return result;
 
         }
 
-        private object UnPackPayloadbyCallError(Queue requestQueue, string uniqueId)
+        private IRequest UnPackPayloadbyCallError(Queue requestQueue, string uniqueId)
         {
-            object sentMsg = requestQueue.RestoreRequest(uniqueId);
+            IRequest sentMsg = requestQueue.RestoreRequest(uniqueId);
 
             return sentMsg;
 

+ 1 - 1
EVCB_OCPP.WSServer/Message/FirmwareManagementProfileHandler.cs

@@ -34,7 +34,7 @@ namespace EVCB_OCPP.WSServer.Message
                             {
                                 var machine = db.Machine.Where(x => x.FW_AssignedMachineVersionId.HasValue == true &&
                                     x.FW_AssignedMachineVersionId != x.FW_VersionReport && x.ChargeBoxId == session.ChargeBoxId)
-                                    .Select(x => new { x.Id, x.FW_AssignedMachineVersionId }).FirstOrDefault();
+                                    .Select(x => new { x.Id, x.FW_AssignedMachineVersionId }).AsNoTracking().FirstOrDefault();
 
                                 if (machine != null)
                                 {

+ 13 - 1
EVCB_OCPP.WSServer/Message/MessageResult.cs

@@ -1,4 +1,5 @@
-using System;
+using EVCB_OCPP.Packet.Messages;
+using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
@@ -39,4 +40,15 @@ namespace EVCB_OCPP.WSServer.Message
 
 
     }
+
+
+    internal class  BasicMessageResult
+    {
+        internal IRequest Request { set; get; }
+
+        internal IConfirmation Confirmation { set; get; }
+
+        internal Exception Exception { get; set; }
+    }
+
 }

+ 22 - 15
EVCB_OCPP.WSServer/ProtalServer.cs

@@ -253,10 +253,10 @@ namespace EVCB_OCPP.WSServer
                     takeCount = StandardConfiguration.AllConfigs.Count - skipCount > takeCount ? takeCount : StandardConfiguration.AllConfigs.Count - skipCount;
 
                     var _keys = StandardConfiguration.AllConfigs.Skip(skipCount).Take(takeCount).ToList();
-                    Console.WriteLine("===============Skip:" + skipCount);
+                 //   Console.WriteLine("===============Skip:" + skipCount);
                     if (_Configure == null)
                     {
-                        Console.WriteLine("_Configure == null===============Skip:" + skipCount);
+                       // Console.WriteLine("_Configure == null===============Skip:" + skipCount);
                         db.ServerMessage.Add(new ServerMessage()
                         {
                             ChargeBoxId = chargeBoxId,
@@ -395,15 +395,17 @@ namespace EVCB_OCPP.WSServer
 
         private void ReceivedMessage(ClientData session, string rawdata)
         {
-
+           
             BasicMessageHandler msgAnalyser = new BasicMessageHandler();
             MessageResult analysisResult = msgAnalyser.AnalysisReceiveData(session, rawdata);
 
-
             WriteMachineLog(session, rawdata,
-                string.Format("{0} {1}", string.IsNullOrEmpty(analysisResult.Action) ? "unknown" : analysisResult.Action, analysisResult.Id == 2 ? "Request" : (analysisResult.Id == 3 ? "Confirmation" : "Error")));
+                 string.Format("{0} {1}", string.IsNullOrEmpty(analysisResult.Action) ? "unknown" : analysisResult.Action, analysisResult.Id == 2 ? "Request" : (analysisResult.Id == 3 ? "Confirmation" : "Error")), string.IsNullOrEmpty(analysisResult.CallErrorMsg) ? "" : analysisResult.Exception.Message);
+
+
 
-            if (analysisResult.Success == false)
+
+            if (!analysisResult.Success)
             {
                 //解析RawData就發生錯誤
                 if (!string.IsNullOrEmpty(analysisResult.CallErrorMsg))
@@ -720,7 +722,7 @@ namespace EVCB_OCPP.WSServer
 
                         var needUpdateChargers = db.Machine.Where(x => x.FW_AssignedMachineVersionId.HasValue == true &&
                           x.FW_AssignedMachineVersionId != x.FW_VersionReport && x.Online == true)
-                          .Select(x => x.ChargeBoxId).ToList();
+                          .Select(x => x.ChargeBoxId).AsNoTracking().ToList();
 
                         foreach (var chargeBoxId in needUpdateChargers)
                         {
@@ -1054,10 +1056,14 @@ namespace EVCB_OCPP.WSServer
 
                     if (clientDic.ContainsKey(session.ChargeBoxId))
                     {
-                        logger.Debug(String.Format("ChargeBoxId:{0} Remove SessionId:{1} Removed SessionId:{2}", session.ChargeBoxId, session.SessionID, clientDic[session.ChargeBoxId].SessionID));
+                        if(clientDic[session.ChargeBoxId].SessionID == session.SessionID)
+                        {
+                            logger.Debug(String.Format("ChargeBoxId:{0} Remove SessionId:{1} Removed SessionId:{2}", session.ChargeBoxId, session.SessionID, clientDic[session.ChargeBoxId].SessionID));
 
-                        clientDic.Remove(session.ChargeBoxId);
-                        logger.Trace("RemoveClient ContainsKey " + session.ChargeBoxId);
+                            clientDic.Remove(session.ChargeBoxId);
+                            logger.Trace("RemoveClient ContainsKey " + session.ChargeBoxId);
+                        }
+                     
                     }
                 }
             }
@@ -1073,11 +1079,12 @@ namespace EVCB_OCPP.WSServer
             }
         }
 
-        private void WriteMachineLog(ClientData evse, string data, string messageType, string errorMsg = "", bool isSent = false)
+        private void WriteMachineLog(ClientData clientData, string data, string messageType, string errorMsg = "", bool isSent = false)
         {
             try
             {
-                if (evse == null || string.IsNullOrEmpty(data)) return;
+                
+                if (clientData == null || string.IsNullOrEmpty(data)) return;
                 using (var db = new ConnectionLogDBContext())
                 {
                     string sp = "[dbo].[uspInsertMachineConnectionLog] @CreatedOn," +
@@ -1086,13 +1093,13 @@ namespace EVCB_OCPP.WSServer
                     SqlParameter[] parameter =
                     {
                       new SqlParameter("CreatedOn",dd),
-                      new SqlParameter("ChargeBoxId",evse.ChargeBoxId.Replace("'","''")),
+                      new SqlParameter("ChargeBoxId",clientData.ChargeBoxId.Replace("'","''")),
                       new SqlParameter("MessageType",messageType.Replace("'","''")),
                       new SqlParameter("Data",data.Replace("'","''")),
                       new SqlParameter("Msg",errorMsg.Replace("'","''")),
                       new  SqlParameter("IsSent",isSent),
-                      new  SqlParameter("EVSEEndPoint",evse.RemoteEndPoint.ToString()),
-                      new  SqlParameter("Session",evse.SessionID)
+                      new  SqlParameter("EVSEEndPoint",clientData.RemoteEndPoint==null?"123":clientData.RemoteEndPoint.ToString()),
+                      new  SqlParameter("Session",clientData.SessionID)
                };
 
                     db.Database.ExecuteSqlCommand(sp, parameter);

+ 1 - 0
EVCB_OCPP.WSServer/SuperSocket.Protocol/ClientData.cs

@@ -28,6 +28,7 @@ namespace OCPPServer.Protocol
         public ClientData()
         {
             IsCheckIn = false;
+            ChargeBoxId = SessionID;
 
         }
 

+ 1 - 1
EVCB_OCPP.WSServer/SuperSocket.Protocol/OCPPWSServer.cs

@@ -68,7 +68,7 @@ namespace OCPPServer.Protocol
             using (var db = new MainDBContext())
             {
                 var machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault();
-                db.Database.ExecuteSqlCommand("delete  FROM [dbo].[MachineConfigures];");
+               
 
                 isExistedSN = machine == null ? false : true;
             }

+ 2 - 0
SuperWebSocket/WebSocketServer.cs

@@ -78,6 +78,8 @@ namespace SuperWebSocket
         {
 
         }
+
+   
     }
 
     /// <summary>

+ 4 - 1
TestTool.RemoteTriggerAPP/App.config

@@ -32,7 +32,10 @@
   <applicationSettings>
     <TestTool.RemoteTriggerAPP.Properties.Settings>
       <setting name="FilePreUrl" serializeAs="String">
-        <value>http://test.evsocket.phihong.com.cn/</value>
+        <value>http://test.evsocket.phihong.com.cn:9001/</value>
+      </setting>
+      <setting name="FTPFilePreUrl" serializeAs="String">
+        <value>ftp://evseocpp:evseocpp@test.evsocket.phihong.com.cn/</value>
       </setting>
     </TestTool.RemoteTriggerAPP.Properties.Settings>
   </applicationSettings>

二進制
TestTool.RemoteTriggerAPP/DLL/EVCB_OCPP.Domain.dll


二進制
TestTool.RemoteTriggerAPP/DLL/EVCB_OCPP.Packet.dll


+ 331 - 0
TestTool.RemoteTriggerAPP/FTPClient.cs

@@ -0,0 +1,331 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace TestTool.RemoteTriggerAPP
+{
+    public class FtpState
+    {
+        private ManualResetEvent wait;
+        private FtpWebRequest request;
+        private string fileName;
+        private Exception operationException = null;
+        private FtpStatusCode status;
+
+        public FtpState()
+        {
+            wait = new ManualResetEvent(false);
+        }
+        public ManualResetEvent OperationComplete
+        {
+            get { return wait; }
+        }
+        public FtpWebRequest Request
+        {
+            get { return request; }
+            set { request = value; }
+        }
+
+        public string FileName
+        {
+            get { return fileName; }
+            set { fileName = value; }
+        }
+        public Exception OperationException
+        {
+            get { return operationException; }
+            set { operationException = value; }
+        }
+        public FtpStatusCode StatusCode
+        {
+            get { return status; }
+            set { status = value; }
+        }
+    }
+    public class FTPClient
+    {
+
+        public delegate void UploadDataCompletedEventHandler(FtpState state);
+        public event UploadDataCompletedEventHandler OnUploadSuccessful;
+        public event UploadDataCompletedEventHandler OnUploadFail;
+        private int uploadTimeOut = 5 * 1000 * 60;
+
+        public string Host
+        {
+            private set; get;
+        }
+        public string UesrName
+        {
+            private set; get;
+        }
+        public string Password
+        {
+            private set; get;
+        }
+
+        public int UploadTimeOut
+        {
+            get
+            {
+                return uploadTimeOut;
+            }
+
+            set
+            {
+                uploadTimeOut = value;
+            }
+        }
+
+        public FTPClient(string host, string usrName, string password)
+        {
+            Host = host;
+            UesrName = usrName;
+            Password = password;
+        }
+
+        /// <summary>
+        /// 上傳檔案到FTPServer(斷點續傳)
+        /// </summary>
+        /// <param name="uploadFilePath">本地上傳檔案的路徑</param>
+        /// <param name="uploadFtpPath">FTPServer上的存放路徑</param>
+        public bool FtpUploadBroken(string uploadFilePath, string uploadFtpPath)
+        {
+            if (uploadFtpPath == null)
+            {
+                uploadFtpPath = "";
+            }
+            string newFileName = string.Empty;
+            bool success = true;
+            FileInfo fileInf = new FileInfo(uploadFilePath);
+            long allbye = (long)fileInf.Length;
+
+            long startfilesize = GetFileSize(uploadFtpPath);
+            if (startfilesize >= allbye)
+            {
+                return false;
+            }
+            long startbye = startfilesize;
+
+
+
+            FtpWebRequest reqFTP;
+            // 根据uri创建FtpWebRequest对象 
+            reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(uploadFtpPath));
+            // ftp用户名和密码 
+            reqFTP.Credentials = new NetworkCredential(UesrName, Password);
+            // 默认为true,连接不会被关闭 
+            // 在一个命令之后被执行 
+            reqFTP.KeepAlive = false;
+            // 指定执行什么命令 
+            reqFTP.Method = WebRequestMethods.Ftp.AppendFile;
+            // 指定数据传输类型 
+            reqFTP.UseBinary = true;
+            // 上传文件时通知服务器文件的大小 
+            reqFTP.ContentLength = fileInf.Length;
+            int buffLength = 2048;// 缓冲大小设置为2kb 
+            byte[] buff = new byte[buffLength];
+            // 打开一个文件流 (System.IO.FileStream) 去读上传的文件 
+            using (FileStream fs = fileInf.OpenRead())
+            {
+                Stream strm = null;
+                try
+                {
+                    // 把上传的文件写入流 
+                    strm = reqFTP.GetRequestStream();
+                    // 每次读文件流的2kb   
+                    fs.Seek(startfilesize, 0);
+                    int contentLen = fs.Read(buff, 0, buffLength);
+                    // 流内容没有结束 
+                    while (contentLen != 0)
+                    {
+                        // 把内容从file stream 写入 upload stream 
+                        strm.Write(buff, 0, contentLen);
+                        contentLen = fs.Read(buff, 0, buffLength);
+                        startbye += contentLen;
+
+                    }
+                    // 关闭两个流 
+                    strm.Close();
+                    fs.Close();
+                }
+                catch(Exception ex)
+                {
+                    success = false;
+
+                }
+                finally
+                {
+                    if (fs != null)
+                    {
+                        fs.Close();
+                    }
+                    if (strm != null)
+                    {
+                        strm.Close();
+                    }
+                }
+            }
+
+            return success;
+        }
+
+        /// <summary>
+        /// 獲取已上傳檔案大小
+        /// </summary>
+        /// <param name="remoteFilepath">服务器文件路径</param>
+        /// <returns></returns>
+        private long GetFileSize(string remoteFilepath)
+        {
+            long filesize = 0;
+            try
+            {
+                FtpWebRequest reqFTP = (FtpWebRequest)FtpWebRequest.Create(remoteFilepath);
+                reqFTP.KeepAlive = false;
+                reqFTP.UseBinary = true;
+                reqFTP.Credentials = new NetworkCredential(UesrName, Password);//用户,密码
+                reqFTP.Method = WebRequestMethods.Ftp.GetFileSize;
+                FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
+                filesize = response.ContentLength;
+                return filesize;
+            }
+            catch
+            {
+                return 0;
+            }
+        }
+
+
+        /// <summary>
+        /// 上傳檔案到FTPServer
+        /// </summary>
+        /// <param name="uploadFilePath">本地上傳檔案的路徑</param>
+        /// <param name="uploadFtpPath">FTPServer上的存放路徑</param>
+        public void UploadFile(string uploadFilePath, string uploadFtpPath)
+        {
+
+            Uri target = new Uri(uploadFtpPath);
+            FtpState state = new FtpState();
+            FtpWebRequest request = (FtpWebRequest)WebRequest.Create(target);
+            request.Method = WebRequestMethods.Ftp.UploadFile;
+            request.Credentials = new NetworkCredential(UesrName, Password);
+            state.Request = request;
+            state.FileName = uploadFilePath;
+
+
+            // Asynchronously get the stream for the file contents.
+            request.BeginGetRequestStream(
+                new AsyncCallback(EndGetStreamCallback),
+                state
+            );
+
+
+            ThreadPool.RegisterWaitForSingleObject(state.OperationComplete, new WaitOrTimerCallback(TimeoutCallback), state, UploadTimeOut, true);
+        }
+        private void EndGetStreamCallback(IAsyncResult ar)
+        {
+            FtpState state = (FtpState)ar.AsyncState;
+
+            Stream requestStream = null;
+            // End the asynchronous call to get the request stream.
+            try
+            {
+                using (requestStream = state.Request.EndGetRequestStream(ar))
+                {
+                    // Copy the file contents to the request stream.
+                    const int bufferLength = 2048;
+                    byte[] buffer = new byte[bufferLength];
+                    int count = 0;
+                    int readBytes = 0;
+                    using (FileStream stream = File.OpenRead(state.FileName))
+                    {
+                        do
+                        {
+                            readBytes = stream.Read(buffer, 0, bufferLength);
+                            requestStream.Write(buffer, 0, readBytes);
+                            count += readBytes;
+
+                        }
+                        while (readBytes != 0);
+                    }
+
+                    Console.WriteLine("Writing {0} bytes to the stream.", count);
+                    // IMPORTANT: Close the request stream before sending the request.
+                    requestStream.Close();
+                }
+
+
+                // Asynchronously get the response to the upload request.
+                state.Request.BeginGetResponse(
+                    new AsyncCallback(EndGetResponseCallback),
+                    state
+                );
+            }
+            // Return exceptions to the main application thread.
+            catch (Exception e)
+            {
+                Console.WriteLine("Could not get the request stream.");
+                state.OperationException = e;
+                state.OperationComplete.Set();
+                //if (OnUploadFail != null)
+                //    OnUploadFail(state);
+            }
+
+        }
+        private void EndGetResponseCallback(IAsyncResult ar)
+        {
+            FtpState state = (FtpState)ar.AsyncState;
+            FtpWebResponse response = null;
+            try
+            {
+                response = (FtpWebResponse)state.Request.EndGetResponse(ar);
+                response.Close();
+                state.StatusCode = response.StatusCode;
+                state.OperationComplete.Set();
+
+
+
+            }
+            // Return exceptions to the main application thread.
+            catch (Exception e)
+            {
+                //Console.WriteLine("Error getting response.");
+                state.OperationException = e;
+                state.OperationComplete.Set();
+                //if (OnUploadFail != null)
+                //    OnUploadFail(state);
+
+            }
+        }
+        private void TimeoutCallback(object state, bool timedOut)
+        {
+            FtpState _state = state as FtpState;
+            if (timedOut)
+            {
+                _state.Request.Abort();
+                if (OnUploadFail != null)
+                    OnUploadFail(_state);
+            }
+            else
+            {
+
+                if (_state.StatusCode == FtpStatusCode.ClosingData)
+                {
+                    if (OnUploadSuccessful != null)
+                        OnUploadSuccessful(_state);
+                }
+                else
+                {
+                    if (OnUploadFail != null)
+                        OnUploadFail(_state);
+                }
+            }
+        }
+
+    }
+
+}

+ 10 - 6
TestTool.RemoteTriggerAPP/MainWindow.xaml

@@ -3,9 +3,9 @@
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
-        xmlns:local="clr-namespace:TestTool.RemoteTriggerAPP"
+        xmlns:local="clr-namespace:TestTool.RemoteTriggerAPP"      
         mc:Ignorable="d"
-        Title="MainWindow" Height="450" Width="670">
+        Title="下發測試用工具(公司內網) V1.1.3(20200218)" Height="450" Width="670">
     <Grid Margin="0,2,0,-2">
         <Label Content="Charge Box Id:" HorizontalAlignment="Left" Height="27" Margin="69,23,0,0" VerticalAlignment="Top" Width="91"/>
         <Label Content="Connector Id:" HorizontalAlignment="Left" Height="27" Margin="336,23,0,0" VerticalAlignment="Top" Width="92"/>
@@ -51,9 +51,9 @@
         <Label Content="ParentId Tag:" HorizontalAlignment="Left" Height="27" Margin="212,74,0,0" VerticalAlignment="Top" Width="87"/>
         <TextBox x:Name="uxParentIdTagTb" Text="TestTool" HorizontalAlignment="Left" Height="27" Margin="299,74,0,0" VerticalAlignment="Top" Width="73" RenderTransformOrigin="3.714,1"/>
         <Label Content="Configuration Key:" HorizontalAlignment="Left" Height="27" Margin="71,119,0,0" VerticalAlignment="Top" Width="120"/>
-        <TextBox x:Name="uxConfigKeyTb" Text="ConnectionTimeOut" HorizontalAlignment="Left" Height="27" Margin="212,119,0,0" VerticalAlignment="Top" Width="138" RenderTransformOrigin="3.714,1"/>
-        <Label Content=" Value:" HorizontalAlignment="Left" Height="27" Margin="374,119,0,0" VerticalAlignment="Top" Width="54"/>
-        <TextBox x:Name="uxConfigValueTb" Text="30" HorizontalAlignment="Left" Height="27" Margin="433,119,0,0" VerticalAlignment="Top" Width="52" RenderTransformOrigin="3.714,1"/>
+        <TextBox x:Name="uxConfigKeyTb" Text="ConnectionTimeOut" HorizontalAlignment="Left" Height="27" Margin="196,119,0,0" VerticalAlignment="Top" Width="138" RenderTransformOrigin="3.714,1"/>
+        <Label Content=" Value:" HorizontalAlignment="Left" Height="27" Margin="339,119,0,0" VerticalAlignment="Top" Width="54"/>
+        <TextBox x:Name="uxConfigValueTb" Text="30" HorizontalAlignment="Left" Height="27" Margin="398,117,0,0" VerticalAlignment="Top" Width="52" RenderTransformOrigin="3.714,1"/>
         <Label  Content="Upload Firmware:" HorizontalAlignment="Left" Height="27" Margin="69,217,0,0" VerticalAlignment="Top" Width="113"/>
 
         <TextBox x:Name="uxUploadFileTb" Text="" HorizontalAlignment="Left" Height="27" Margin="182,217,0,0" VerticalAlignment="Top" Width="210" RenderTransformOrigin="3.714,1"/>
@@ -65,6 +65,10 @@
         <Button x:Name="uxPublishBtn" Content="Publish" HorizontalAlignment="Left" Margin="476,266,0,0" VerticalAlignment="Top" Width="53" Height="34" Click="uxPublishBtn_Click"/>
         <Label Content="ReservationId:" HorizontalAlignment="Left" Height="27" Margin="480,23,0,0" VerticalAlignment="Top" Width="100"/>
         <TextBox x:Name="uxReservationTb" Text="0" HorizontalAlignment="Left" Height="27" Margin="585,23,0,0" VerticalAlignment="Top" Width="44" RenderTransformOrigin="3.714,1"/>
-
+        <Button x:Name="uxClearPublishBtn" Content="Clear Publish" HorizontalAlignment="Left" Margin="543,266,0,0" VerticalAlignment="Top" Width="86" Height="34" Click="uxClearPublishBtn_Click"/>
+        <Button x:Name="uxFTPUploadBtn" Content="Upload(FTP)" HorizontalAlignment="Left" Margin="543,212,0,0" VerticalAlignment="Top" Width="86" Height="34" Click="uxFTPUploadBtn_Click" RenderTransformOrigin="2.058,0.529"/>
+        <Label Content=" Expiry Time:" HorizontalAlignment="Left" Height="27" Margin="455,119,0,0" VerticalAlignment="Top" Width="80"/>
+        
+        <TextBox x:Name="uxExpiryTimeTb"  Margin="543,117,10,273" Text="2020/02/06 12:00"></TextBox>
     </Grid>
 </Window>

+ 153 - 35
TestTool.RemoteTriggerAPP/MainWindow.xaml.cs

@@ -44,8 +44,9 @@ namespace TestTool.RemoteTriggerAPP
         int selectedPublish = -1;
         public MainWindow()
         {
-           
+
             InitializeComponent();
+
         }
 
         private void UxSubmitBtn_Click(object sender, RoutedEventArgs e)
@@ -202,7 +203,7 @@ namespace TestTool.RemoteTriggerAPP
                     connectorId = Convert.ToInt32(uxConnectorIdTb.Text),
                     csChargingProfiles = new csChargingProfiles()
                     {
-                        chargingProfileId = Convert.ToInt32(DateTime.Now.ToString("yyMMddHHmm")),
+                        chargingProfileId = Convert.ToInt32(DateTime.Now.ToUniversalTime().ToString("yyMMddHHmm")),
                         chargingProfileKind = ChargingProfileKindType.Absolute,
                         chargingProfilePurpose = isDefault ? ChargingProfilePurposeType.TxDefaultProfile : ChargingProfilePurposeType.TxProfile,
                         recurrencyKind = RecurrencyKindType.Daily,
@@ -212,7 +213,7 @@ namespace TestTool.RemoteTriggerAPP
                             chargingRateUnit = ChargingRateUnitType.A,
                             duration = 300,
                             minChargingRate = 0,
-                            startSchedule = DateTime.Now.Date,
+                            startSchedule = DateTime.Now.ToUniversalTime().Date,
                             chargingSchedulePeriod = new List<ChargingSchedulePeriod>()
                                         {
                                              new ChargingSchedulePeriod()
@@ -300,23 +301,45 @@ namespace TestTool.RemoteTriggerAPP
 
         private void ReserveNow()
         {
-
+            bool isError = false;
+            DateTime expiryTime = DateTime.Now;
             try
             {
-
-                var uuid = Guid.NewGuid().ToString();
-                var request = new ReserveNowRequest()
+                try
                 {
-                    connectorId = Convert.ToInt32(uxConnectorIdTb.Text),
-                    expiryDate = DateTime.Now.AddDays(5),
-                    idTag = uxIdTagTb.Text,
-                    parentIdTag = "PTAG",
-                    reservationId = Convert.ToInt32(DateTime.Now.ToString("yyMMddHHmm")),
+                     expiryTime = Convert.ToDateTime(uxExpiryTimeTb.Text);
+                    if(expiryTime <DateTime.Now.AddSeconds(60))
+                    {
+                        isError = true;
+                        uxMsgTb.Text = string.Format("ExpiryTime is too close or too early to the current time (60 seconds).");
+                    }
+                 
+                }
+                catch (Exception ex)
+                {
+                    if (ex is FormatException)
+                    {
+                        isError = true;
+                        uxMsgTb.Text = string.Format("ExpiryTime's Format is wrong Example:{0}",DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"));
+                    }
+                }
+                if (!isError)
+                {
+                    var uuid = Guid.NewGuid().ToString();
+                    var request = new ReserveNowRequest()
+                    {
+                        connectorId = Convert.ToInt32(uxConnectorIdTb.Text),
+                        expiryDate = expiryTime.ToUniversalTime(),
+                        idTag = uxIdTagTb.Text,
+                        parentIdTag = "PTAG",
+                        reservationId = Convert.ToInt32(expiryTime.ToUniversalTime().ToString("yyMMddHHmm")),
 
-                };
+                    };
+
+                    WritetoDB(uuid, request);
+                    uxMsgTb.Text = string.Format("UUID:{0}", uuid);
+                }
 
-                WritetoDB(uuid, request);
-                uxMsgTb.Text = string.Format("UUID:{0}", uuid);
             }
             catch (Exception ex)
             {
@@ -332,12 +355,12 @@ namespace TestTool.RemoteTriggerAPP
                 var uuid = Guid.NewGuid().ToString();
                 var request = new GetDiagnosticsRequest()
                 {
-            
+
                     location = new Uri("ftp://phihong:y42j%2f4cj84@test.evsocket.phihong.com.cn/"),
                     retries = 1,
                     retryInterval = 30,
-                    startTime = DateTime.Now.AddHours(-1),
-                    stopTime = DateTime.Now
+                    startTime = DateTime.Now.AddHours(-1).ToUniversalTime(),
+                    stopTime = DateTime.Now.ToUniversalTime()
 
 
                 };
@@ -381,18 +404,18 @@ namespace TestTool.RemoteTriggerAPP
                 var uuid = Guid.NewGuid().ToString();
                 var request = new SendLocalListRequest()
                 {
-                    listVersion = Convert.ToInt32(DateTime.Now.ToString("yyMMddHHmm")),
+                    listVersion = Convert.ToInt32(DateTime.Now.ToUniversalTime().ToString("yyMMddHHmm")),
                     updateType = isFull ? UpdateType.Full : UpdateType.Differential,
                     localAuthorizationList = new List<AuthorizationData>()
                     {
                          new AuthorizationData()
                          {
 
-                              idTagInfo=new IdTagInfo(){  expiryDate=DateTime.Now.AddDays(3), status=  AuthorizationStatus.Accepted},
+                              idTagInfo=new IdTagInfo(){  expiryDate=DateTime.Now.ToUniversalTime().AddDays(3), status=  AuthorizationStatus.Accepted},
                                idTag="123"
                          }, new AuthorizationData()
                          {
-                              idTagInfo=new IdTagInfo(){  expiryDate=DateTime.Now.AddDays(3), status=  AuthorizationStatus.Expired},
+                              idTagInfo=new IdTagInfo(){  expiryDate=DateTime.Now.ToUniversalTime().AddDays(3), status=  AuthorizationStatus.Expired},
                                idTag="456"
                          }
                     }
@@ -473,7 +496,7 @@ namespace TestTool.RemoteTriggerAPP
                 {
                     request.chargingProfile = new csChargingProfiles()
                     {
-                        chargingProfileId = Convert.ToInt32(DateTime.Now.ToString("yyMMddHHmm")),
+                        chargingProfileId = Convert.ToInt32(DateTime.Now.ToUniversalTime().ToString("yyMMddHHmm")),
                         chargingProfileKind = ChargingProfileKindType.Absolute,
                         chargingProfilePurpose = ChargingProfilePurposeType.TxProfile,
                         recurrencyKind = RecurrencyKindType.Daily,
@@ -483,7 +506,7 @@ namespace TestTool.RemoteTriggerAPP
                             chargingRateUnit = ChargingRateUnitType.A,
                             duration = 300,
                             minChargingRate = 0,
-                            startSchedule = DateTime.Now.Date,
+                            startSchedule = DateTime.Now.ToUniversalTime().Date,
                             chargingSchedulePeriod = new List<ChargingSchedulePeriod>()
                                         {
                                              new ChargingSchedulePeriod()
@@ -698,7 +721,7 @@ namespace TestTool.RemoteTriggerAPP
             {
                 db.MachineOperateRecord.Add(new MachineOperateRecord()
                 {
-                    CreatedOn = DateTime.Now,
+                    CreatedOn = DateTime.Now.ToUniversalTime(),
                     ChargeBoxId = uxChargeBoxIdTb.Text,
                     SerialNo = uuid,
                     RequestContent = JsonConvert.SerializeObject(request, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
@@ -712,7 +735,7 @@ namespace TestTool.RemoteTriggerAPP
                 {
                     ChargeBoxId = uxChargeBoxIdTb.Text,
                     CreatedBy = "TestTool",
-                    CreatedOn = DateTime.Now,
+                    CreatedOn = DateTime.Now.ToUniversalTime(),
                     OutAction = request.Action.ToString(),
                     OutRequest = JsonConvert.SerializeObject(request, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
                     SerialNo = uuid,
@@ -744,6 +767,7 @@ namespace TestTool.RemoteTriggerAPP
             }
 
             FileInfo f = new FileInfo(uxUploadFileTb.Text);
+
             int size = (int)f.Length;
             string md5 = "";
             string filePreUrl = ConfigurationManager.AppSettings["FilePreUrl"];
@@ -756,16 +780,12 @@ namespace TestTool.RemoteTriggerAPP
                     var _md5 = MD5.Create();
                     var hash = _md5.ComputeHash(fileStream);
                     md5 = BitConverter.ToString(hash).Replace("-", String.Empty).ToLowerInvariant();
-                    //using (Stream requestStream = client.OpenWrite(new Uri(@filePreUrl + "UploadFiles/Fw/" + ufObj.FileName), "POST"))
-                    //{
 
-                    //    fileStream.CopyTo(requestStream);
-                    //}
                 }
             }
 
             UploadFile ufObj = new UploadFile();
-            ufObj.CreatedOn = DateTime.Now;
+            ufObj.CreatedOn = DateTime.Now.ToUniversalTime();
             ufObj.FileExtensionName = System.IO.Path.GetExtension(uxUploadFileTb.Text);
             ufObj.Id = Guid.NewGuid();
             ufObj.FileName = md5 + ufObj.FileExtensionName;
@@ -774,15 +794,16 @@ namespace TestTool.RemoteTriggerAPP
             ufObj.FileMD5 = md5;
             ufObj.CustomerId = new Guid("8456AED9-6DD9-4BF3-A94C-9F5DCB9506F7");
             ufObj.OriginName = System.IO.Path.GetFileName(uxUploadFileTb.Text);
-            ufObj.FileUrl = new Uri(Properties.Settings.Default.FilePreUrl + ufObj.FilePath.Replace("~/","")).ToString();
+            ufObj.FileUrl = new Uri(Properties.Settings.Default.FilePreUrl + ufObj.FilePath.Replace("~/", "")).ToString();
             ufObj.IsOnline = true;
 
+
             using (var db = new MainDBContext())
             {
                 db.UploadFile.Add(ufObj);
                 db.SaveChanges();
                 var pvQry = db.PublishVersion.Where(x => x.CustomerMachineComponentId == 1).OrderByDescending(c => c.Version).FirstOrDefault();
-                PublishVersion pv = new PublishVersion { CustomerMachineComponentId = 1, CreatedOn = DateTime.Now, Version = 1 };
+                PublishVersion pv = new PublishVersion { CustomerMachineComponentId = 1, CreatedOn = DateTime.Now.ToUniversalTime(), Version = 1 };
                 if (pvQry != null)
                 {
                     pv.Version = pvQry.Version + 1;
@@ -792,11 +813,80 @@ namespace TestTool.RemoteTriggerAPP
                 db.SaveChanges();
             }
 
+            FTPClient UploadClient = new FTPClient(@"ftp://test.evsocket.phihong.com.cn", "testocpp", "testocpp");
+            bool uploadResult = UploadClient.FtpUploadBroken(uxUploadFileTb.Text, @"ftp://test.evsocket.phihong.com.cn/" + ufObj.FileName);
+
+
 
-            uxMsgTb.Text = "write to DB ,but you must manaul upload file to server and filename replace with " + ufObj.FileName;
+            uxMsgTb.Text = "Upload File Result :" + (uploadResult ? "Success" : "Fail");
 
         }
 
+
+        private void uxFTPUploadBtn_Click(object sender, RoutedEventArgs e)
+        {
+            if (string.IsNullOrEmpty(uxUploadFileTb.Text))
+            {
+                uxMsgTb.Text = "Please select upload file!";
+                return;
+            }
+
+            FileInfo f = new FileInfo(uxUploadFileTb.Text);
+
+            int size = (int)f.Length;
+            string md5 = "";
+
+            using (WebClient client = new WebClient())
+            {
+                client.UseDefaultCredentials = false;
+                client.Headers.Add("Content-Type", "application/octet-stream");
+                using (Stream fileStream = File.OpenRead(uxUploadFileTb.Text))
+                {
+                    var _md5 = MD5.Create();
+                    var hash = _md5.ComputeHash(fileStream);
+                    md5 = BitConverter.ToString(hash).Replace("-", String.Empty).ToLowerInvariant();
+
+                }
+            }
+
+            UploadFile ufObj = new UploadFile();
+            ufObj.CreatedOn = DateTime.Now.ToUniversalTime();
+            ufObj.FileExtensionName = System.IO.Path.GetExtension(uxUploadFileTb.Text);
+            ufObj.Id = Guid.NewGuid();
+            ufObj.FileName = md5 + ufObj.FileExtensionName;
+            ufObj.FilePath = "~/UploadFiles/Fw/" + ufObj.FileName;
+            ufObj.FileSize = size;
+            ufObj.FileMD5 = md5;
+            ufObj.CustomerId = new Guid("8456AED9-6DD9-4BF3-A94C-9F5DCB9506F7");
+            ufObj.OriginName = System.IO.Path.GetFileName(uxUploadFileTb.Text);
+            ufObj.FileUrl = new Uri(Properties.Settings.Default.FTPFilePreUrl + ufObj.FileName).ToString();
+            ufObj.IsOnline = true;
+
+
+            using (var db = new MainDBContext())
+            {
+                db.UploadFile.Add(ufObj);
+                db.SaveChanges();
+                var pvQry = db.PublishVersion.Where(x => x.CustomerMachineComponentId == 1).OrderByDescending(c => c.Version).FirstOrDefault();
+                PublishVersion pv = new PublishVersion { CustomerMachineComponentId = 1, CreatedOn = DateTime.Now.ToUniversalTime(), Version = 1 };
+                if (pvQry != null)
+                {
+                    pv.Version = pvQry.Version + 1;
+                }
+                pv.PublishVersionFiles.Add(new PublishVersionFile() { UploadFileId = ufObj.Id });
+                db.PublishVersion.Add(pv);
+                db.SaveChanges();
+            }
+
+            FTPClient UploadClient = new FTPClient(@"ftp://test.evsocket.phihong.com.cn", "testocpp", "testocpp");
+            bool uploadResult = UploadClient.FtpUploadBroken(uxUploadFileTb.Text, @"ftp://test.evsocket.phihong.com.cn/" + ufObj.FileName);
+
+
+
+            uxMsgTb.Text = "Upload File Result :" + (uploadResult ? "Success" : "Fail");
+        }
+
+
         private void uxRefreshBtn_Click(object sender, RoutedEventArgs e)
         {
             using (var db = new MainDBContext())
@@ -814,7 +904,9 @@ namespace TestTool.RemoteTriggerAPP
                 uxPublishCb.Items.Clear();
                 foreach (var i in publishes)
                 {
+                    string prefix = i.PublishVersionFiles.FirstOrDefault().UploadFile.FileUrl.StartsWith("ftp") ? "FTP" : "HTTP";
                     sb.Clear();
+                    sb.Append(string.Format("[{0}]", prefix));
                     sb.Append("_版本號:");
                     sb.Append(i.Version);
                     sb.Append("_上傳日期:");
@@ -843,9 +935,18 @@ namespace TestTool.RemoteTriggerAPP
             {
 
                 var machine = db.Machine.Where(x => x.ChargeBoxId == uxChargeBoxIdTb.Text).FirstOrDefault();
-                MachineVersion obj = new MachineVersion() { MachineId = machine.Id, PublishVersionId = publishes[selectedPublish].Id, CreatedOn = DateTime.Now };
+                MachineVersion obj = new MachineVersion()
+                {
+                    MachineId = machine.Id,
+                    PublishVersionId = publishes[selectedPublish].Id,
+                    CreatedOn = DateTime.Now.ToUniversalTime()
+                };
 
-                obj.MachineVersionFiles.Add(new MachineVersionFile() { UploadFileId = publishes[selectedPublish].PublishVersionFiles.First().UploadFileId, CreatedOn = DateTime.Now });
+                obj.MachineVersionFiles.Add(new MachineVersionFile()
+                {
+                    UploadFileId = publishes[selectedPublish].PublishVersionFiles.First().UploadFileId,
+                    CreatedOn = DateTime.Now.ToUniversalTime()
+                });
                 db.MachineVersion.Add(obj);
 
                 //將machine的軟體更新更新到這個值
@@ -865,5 +966,22 @@ namespace TestTool.RemoteTriggerAPP
             selectedPublish = uxPublishCb.SelectedIndex;
 
         }
+
+        private void uxClearPublishBtn_Click(object sender, RoutedEventArgs e)
+        {
+            using (var db = new MainDBContext())
+            {
+
+                var machine = db.Machine.Where(x => x.ChargeBoxId == uxChargeBoxIdTb.Text).FirstOrDefault();
+                machine.FW_AssignedVersion = null;
+                machine.FW_AssignedMachineVersionId = null;
+                db.SaveChanges();
+            }
+
+            uxMsgTb.Text = "Clear Publish";
+
+        }
+
+
     }
 }

+ 10 - 1
TestTool.RemoteTriggerAPP/Properties/Settings.Designer.cs

@@ -25,11 +25,20 @@ namespace TestTool.RemoteTriggerAPP.Properties {
         
         [global::System.Configuration.ApplicationScopedSettingAttribute()]
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-        [global::System.Configuration.DefaultSettingValueAttribute("http://test.evsocket.phihong.com.cn/")]
+        [global::System.Configuration.DefaultSettingValueAttribute("http://test.evsocket.phihong.com.cn:9001/")]
         public string FilePreUrl {
             get {
                 return ((string)(this["FilePreUrl"]));
             }
         }
+        
+        [global::System.Configuration.ApplicationScopedSettingAttribute()]
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        [global::System.Configuration.DefaultSettingValueAttribute("ftp://evseocpp:evseocpp@test.evsocket.phihong.com.cn/")]
+        public string FTPFilePreUrl {
+            get {
+                return ((string)(this["FTPFilePreUrl"]));
+            }
+        }
     }
 }

+ 4 - 1
TestTool.RemoteTriggerAPP/Properties/Settings.settings

@@ -3,7 +3,10 @@
   <Profiles />
   <Settings>
     <Setting Name="FilePreUrl" Type="System.String" Scope="Application">
-      <Value Profile="(Default)">http://test.evsocket.phihong.com.cn/</Value>
+      <Value Profile="(Default)">http://test.evsocket.phihong.com.cn:9001/</Value>
+    </Setting>
+    <Setting Name="FTPFilePreUrl" Type="System.String" Scope="Application">
+      <Value Profile="(Default)">ftp://evseocpp:evseocpp@test.evsocket.phihong.com.cn/</Value>
     </Setting>
   </Settings>
 </SettingsFile>

+ 1 - 0
TestTool.RemoteTriggerAPP/TestTool.RemoteTriggerAPP.csproj

@@ -80,6 +80,7 @@
       <DependentUpon>App.xaml</DependentUpon>
       <SubType>Code</SubType>
     </Compile>
+    <Compile Include="FTPClient.cs" />
     <Compile Include="MainWindow.xaml.cs">
       <DependentUpon>MainWindow.xaml</DependentUpon>
       <SubType>Code</SubType>