using Evcb.Domain.Model; using Evcb.Domain.mongo; using Evcb.Repository; using Evcb.Service; using Evcb.Service.Helpers; using Evcb.Service.Service; using MongoDB.Driver; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NLog; using OCPPPacket.Packet.Feature; using OCPPPacket.Packet.Messages; using OCPPPacket.Packet.Messages.Basic; using OCPPPacket.Packet.Messages.Core; using OCPPPacket.Packet.Status; using OCPPServer.Handler; using OCPPServer.Protocol; using OCPPServer.SubProtocol; using Packet; using Packet.Cmd; using SuperSocket.SocketBase; using SuperSocket.SocketBase.Config; using System; using System.Collections.Generic; using System.Configuration; using System.Data.Entity; using System.Data.Entity.Validation; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Xml.Linq; namespace OCPPServer { public class WSServer { private readonly Object _lockClientDic = new object(); private readonly Object _lockConfirmPacketList = new object(); private CancellationTokenSource _cts = new CancellationTokenSource(); private CancellationToken _ct; private IMongoService mongoService = new MongoService(); static private ILogger logger = NLog.LogManager.GetCurrentClassLogger(); private List _cmd202lst = new List(); private List _needConfirmCmdList; public Dictionary ClientDic { get; set; } public string Listening { get; set; } public string ApiUrl { get; set; } public List NeedConfirmPacketList { get; set; } /// /// 上次校時時間 /// private DateTime sendTiming { get; set; } /// /// 檢查軟韌體時間 /// private DateTime checkUpdateDt { get; set; } /// /// 可允許連線Clinet數 /// public int connectNum { get; set; } /// /// 是否限制連線Clinet數 /// public bool beConnectLimit { get; set; } /// /// 是否紀錄與充電樁互傳命令 在 MachineConnectionLog /// private bool ENABLELOG_MACHINECMD = false; public WSServer() { using (var db = new PhihongDbContext()) { _ct = _cts.Token; ClientDic = new Dictionary(); NeedConfirmPacketList = new List(); //需要確認回傳的指令 _needConfirmCmdList = db.NeedConfirmCmd.Select(c => c.Id).ToList(); //載入相關config ENABLELOG_MACHINECMD = ConfigurationManager.AppSettings.Get("EnableMachineConnectionLog").Equals("0") ? false : true; ApiUrl = ConfigurationManager.AppSettings.Get("ApiUrl"); string serverIp = ConfigurationManager.AppSettings.Get("ServerIp"); string serverPort = ConfigurationManager.AppSettings.Get("ServerPort"); string wssserverPort = ConfigurationManager.AppSettings.Get("WSSServerPort"); string serverSecurity = ConfigurationManager.AppSettings.Get("ServerSecurity"); int maxRequestLength = int.Parse(ConfigurationManager.AppSettings.Get("MaxRequestLength")); var config = ConfigurationManager.GetSection("superSocket") as IConfigurationSource; ICertificateConfig Certificate = config.Servers.ElementAt(0).Certificate; sendTiming = DateTime.Now; checkUpdateDt = DateTime.Now; //載入OCPP Protocol var appServer = new OCPPWSServer(new OCPPSubProtocol()); List llistener = new List(); llistener.Add(new ListenerConfig { Ip = serverIp, Port = Convert.ToInt32(wssserverPort), Backlog = 100, Security = serverSecurity }); llistener.Add(new ListenerConfig { Ip = serverIp, Port = Convert.ToInt32(serverPort), Backlog = 100, Security = "None" }); IEnumerable listeners = llistener; //設定server config var serverConfig = new ServerConfig { //Port = Convert.ToInt32(serverPort), //Ip = serverIp, MaxRequestLength = maxRequestLength, //Security = serverSecurity, Certificate = Certificate, Listeners = listeners }; //Setup with listening port if (!appServer.Setup(serverConfig, logFactory: new OCPPLogFactory())) { Console.WriteLine("Failed to setup!"); Console.ReadKey(); return; } appServer.NewSessionConnected += AppServer_NewSessionConnected; appServer.SessionClosed += AppServer_SessionClosed; Console.WriteLine(); string mac = ConfigurationManager.AppSettings.Get("mac"); string limit = ConfigurationManager.AppSettings.Get("limit"); string signature = ConfigurationManager.AppSettings.Get("Signature"); appServer.beConnectLimit = true; Console.Write("<=============================================================== \n"); Console.Write("Server Mac: {0}\n", mac); Console.Write("Connection Limit: {0}\n", limit); Console.Write("Signature: {0}\n", signature); var result = ConnectionLimitHepler.ConnectionLimitValidation(ConnectionLimitHepler.Key, signature, mac, limit); if (result.IsValid == true) { Console.Write("Verification Signature Result : correct\n"); if (limit.Contains("∞") == false) { appServer.connectNum = Int32.Parse(limit); Console.Write("Real Connection Limit: {0}\n", appServer.connectNum); } else { appServer.connectNum = 0; appServer.beConnectLimit = false; Console.Write("Real Connection Limit: {0}\n", "∞"); } } else { Console.Write("Verification Signature Result : incorrect\n"); appServer.connectNum = 10; Console.Write("Real Connection Limit: {0}\n", appServer.connectNum); } Console.Write("===============================================================> \n"); //Try to start the appServer if (!appServer.Start()) { Console.WriteLine("Failed to start!"); Console.ReadKey(); return; } } } public void Start() { Task taskServerCommand = new Task(ServerCommandThread, _ct); taskServerCommand.Start(); while (true) { var input = Console.ReadLine(); switch (input.ToLower()) { case "stop": //ListenerSocket.Shutdown(SocketShutdown.Both); //ListenerSocket.Close(); Stop(); logger.Info("server stop"); Task.WaitAny(taskServerCommand); break; case "gc": logger.Info("Command GC"); GC.Collect(); break; case "lc": logger.Info("Command List Clients"); var list = ClientDic.Select(c => c.Value).ToList(); int i = 1; foreach (var c in list) { logger.Info(i + ":" + c.MachineCustomId); i++; } break; case "lcn": logger.Info("Command List Customer Name"); var lcn = ClientDic.Select(c => c.Value.CustomerName).Distinct().ToList(); int iLcn = 1; foreach (var c in lcn) { logger.Info(iLcn + ":" + c + ":" + ClientDic.Where(z => z.Value.CustomerName == c).Count().ToString()); iLcn++; } break; case "help": logger.Info("Command help!!"); logger.Info("lcn : List Customer Name"); logger.Info("gc : GC Collect"); logger.Info("lc : List Clients"); logger.Info("cls : clear console"); logger.Info("silent : silent"); logger.Info("show : show log"); logger.Info("rcl : show Real Connection Limit"); break; case "cls": logger.Info("Command clear"); Console.Clear(); break; case "silent": logger.Info("Command silent"); var xe = XElement.Load("NLog.config"); var xns = xe.GetDefaultNamespace(); var minlevelattr = xe.Descendants(xns + "rules").Elements(xns + "logger") .Where(c => c.Attribute("writeTo").Value.Equals("console")).Attributes("minlevel").FirstOrDefault(); if (minlevelattr != null) { minlevelattr.Value = "info"; } xe.Save("NLog.config"); break; case "show": logger.Info("Command show"); var xe1 = XElement.Load("NLog.config"); var xns1 = xe1.GetDefaultNamespace(); var minlevelattr1 = xe1.Descendants(xns1 + "rules").Elements(xns1 + "logger") .Where(c => c.Attribute("writeTo").Value.Equals("console")).Attributes("minlevel").FirstOrDefault(); if (minlevelattr1 != null) { minlevelattr1.Value = "trace"; } xe1.Save("NLog.config"); break; case "rcl": logger.Info("Command rcln"); if (beConnectLimit == true) { logger.Info("Real Connection Limit:" + connectNum); } else { logger.Info("Real Connection Limit:" + "∞"); } break; default: break; } } } /// /// 處理電樁送的OCPP 訊息 /// public void ReceivedMessage(ClientData ctdata, String msg) { using (var db = new PhihongDbContext()) { IUnitOfWork uow = new UnitOfWork(db); IMachineService machineSrv = new MachineService(uow); ISocketCommandService socketCommandSrv = new SocketCommandService(uow); ICustomerService _customerService = new CustomerService(); OCPPMessageHandler ocppMsgHandler = new OCPPMessageHandler(); try { //檢查是否有Connection 沒有加入ClientDic if (ctdata.IsCheckIn) { lock (_lockClientDic) { if (!ClientDic.ContainsKey(ctdata.MachineCustomId)) { ClientDic.Add(ctdata.MachineCustomId, ctdata); logger.Trace("Rejoin MachineCustomId: {0}", ctdata.MachineCustomId); } } } BaseMessage message = ocppMsgHandler.Parse(msg); CheckConfirmPacket(ctdata, message); if (message is CallResultMessage) { #region 處理CallResultMessage //更新充電樁的心跳包接收時間 socketCommandSrv.UpdateHeartbeat(ctdata.MachineCustomId); CallResultMessage call = (CallResultMessage)message; string callResultAction = string.Empty; var result = ocppMsgHandler.OnCallResult(call.id, call.payload, ref ctdata.queue, out callResultAction); if (result.Success == true) { if (ENABLELOG_MACHINECMD) { MachineConnectionLog log = new MachineConnectionLog(); log.MachineCustomId = ctdata.MachineCustomId; log.MachineId = ctdata.MachineId; log.IpPort = ctdata.LocalEndPoint.ToString(); log.IsIllegal = false; if (msg.Length >= 2000) log.Data = msg.Substring(0, 1999); else log.Data = msg; log.IsDataOut = false; log.CmdNum = 0; log.CreatedOn = DateTime.Now; log.Msg = callResultAction; var ep = ((IPEndPoint)ctdata.RemoteEndPoint); log.ClientIpPort = ep.Address.ToString() + ":" + ep.Port.ToString(); SaveMachineConnectionLog(log); if (msg.Length >= 2000) // GetConfiguration.conf封包 { MachineConnectionLog log1 = new MachineConnectionLog(); log1.MachineCustomId = ctdata.MachineCustomId; log1.MachineId = ctdata.MachineId; log1.IpPort = ctdata.LocalEndPoint.ToString(); log1.IsIllegal = false; log1.IsDataOut = false; log1.CmdNum = 0; log1.Data = "config :" + msg.Substring(2000, msg.Length - 2000); log1.CreatedOn = DateTime.Now; log1.Msg = callResultAction; var ep1 = ((IPEndPoint)ctdata.RemoteEndPoint); log1.ClientIpPort = ep1.Address.ToString() + ":" + ep1.Port.ToString(); SaveMachineConnectionLog(log1); } } if (!ctdata.IsCheckIn && (result.Payload is GetConfigurationConfirmation)) { IRequest req = MakeRequestHandler.MakeChangeConfigurationRequest("HeartBeatInterval", "60"); string uuid = ctdata.queue.store(req); Send(ctdata, ocppMsgHandler.GenerateCall(uuid, Actions.ChangeConfiguration.ToString(), req), "ChangeConfiguration Request"); } //將OCPP CallResult Message的Payload所夾帶參數資訊進行處理 var handleConfirmationResult = ocppMsgHandler.HandleConfirmation(call.id, (IConfirmation)result.Payload, callResultAction, db, ref ctdata); if (handleConfirmationResult.Success == true) { //do nothing } else { if (ENABLELOG_MACHINECMD) { //紀錄error type message MachineConnectionLog log1 = new MachineConnectionLog(); log1.MachineCustomId = ctdata.MachineCustomId; log1.MachineId = ctdata.MachineId; log1.IpPort = ctdata.LocalEndPoint.ToString(); log1.IsIllegal = true; log1.IsDataOut = false; log1.CmdNum = 0; log1.Data = msg; log1.CreatedOn = DateTime.Now; log1.Msg = handleConfirmationResult.Message; var ep1 = ((IPEndPoint)ctdata.RemoteEndPoint); log1.ClientIpPort = ep1.Address.ToString() + ":" + ep1.Port.ToString(); SaveMachineConnectionLog(log1); } //送出錯誤訊息給電樁 //Send(ctdata, handleConfirmationResult.Message); } } else { #region error type message 處理 if(result.Message.Equals("none") == true) { //重複送相同Message, 不處理 } else { if (ENABLELOG_MACHINECMD) { //紀錄error type message MachineConnectionLog log = new MachineConnectionLog(); log.MachineCustomId = ctdata.MachineCustomId; log.MachineId = ctdata.MachineId; log.IpPort = ctdata.LocalEndPoint.ToString(); log.IsIllegal = true; log.IsDataOut = false; log.CmdNum = 0; log.Data = msg; log.CreatedOn = DateTime.Now; //紀錄exception, 送出錯誤訊息給電樁 if (result.Exception != null) { logger.Error(result.Exception, "OnCallResult error"); log.Msg = result.Exception.ToString(); } else { ////送出錯誤訊息給電樁 //Send(ctdata, result.Message, "Error Message"); log.Msg = result.Message; } var ep = ((IPEndPoint)ctdata.RemoteEndPoint); log.ClientIpPort = ep.Address.ToString() + ":" + ep.Port.ToString(); SaveMachineConnectionLog(log); } Send(ctdata, result.Message, "Error Message"); } #endregion error type message 處理 } #endregion 處理CallResultMessage } else if (message is CallErrorMessage) { #region 處理CallErrorMessage //failedFlag = true; //更新充電樁的心跳包接收時間 socketCommandSrv.UpdateHeartbeat(ctdata.MachineCustomId); CallErrorMessage call = (CallErrorMessage)message; var result = ocppMsgHandler.OnError(call.id, call.ErrorCode, call.ErrorDescription, call.payload); if (result.Success == true) { if (ENABLELOG_MACHINECMD) { MachineConnectionLog log = new MachineConnectionLog(); log.MachineCustomId = ctdata.MachineCustomId; log.MachineId = ctdata.MachineId; log.IpPort = ctdata.LocalEndPoint.ToString(); log.IsIllegal = false; log.Data = msg;//call.id.ToString() + "," + JsonConvert.SerializeObject(result.Payload); ; log.IsDataOut = false; log.CmdNum = 0; log.CreatedOn = DateTime.Now; log.Msg = call.ErrorCode; var ep = ((IPEndPoint)ctdata.RemoteEndPoint); log.ClientIpPort = ep.Address.ToString() + ":" + ep.Port.ToString(); SaveMachineConnectionLog(log); } //重送上次未成功的訊息 或 移除Client } var handleErrorResult = ocppMsgHandler.HandleError(call.id, call.ErrorCode, call.ErrorDescription, call.payload); #endregion 處理CallErrorMessage } else if (message is CallMessage) { #region 處理CallMessage //處理OCPP Call Message CallMessage call = (CallMessage)message; var result = ocppMsgHandler.OnCall(call.id, call.action, call.payload); bool BootNotificationPending = false; if (result.Success == true) { //如果沒有 check in,設定為illegal的封包資料,紀錄之後,此筆放棄,處理下一個 if (!ctdata.IsCheckIn) { if (ENABLELOG_MACHINECMD) { MachineConnectionLog log = new MachineConnectionLog(); log.MachineCustomId = ctdata.MachineCustomId; log.MachineId = ctdata.MachineId; log.IpPort = ctdata.LocalEndPoint.ToString(); log.IsIllegal = true; log.Data = msg; log.IsDataOut = false; log.CmdNum = 0; log.CreatedOn = DateTime.Now; log.Msg = call.action + " Request"; var ep = ((IPEndPoint)ctdata.RemoteEndPoint); log.ClientIpPort = ep.Address.ToString() + ":" + ep.Port.ToString(); SaveMachineConnectionLog(log); } //如果不是 BootNotificationRequest 就不處理,處理下一個指令 if (!(result.Payload is BootNotificationRequest)) { return; } else { if (ENABLELOG_MACHINECMD) { //紀錄收到BootNotificationRequest(目前還沒有CheckIn) MachineConnectionLog log2 = new MachineConnectionLog(); log2.MachineCustomId = ctdata.MachineCustomId; log2.MachineId = ctdata.MachineId; log2.IpPort = ctdata.LocalEndPoint.ToString(); log2.IsIllegal = false; log2.Data = msg;//call.id.ToString() + "," + call.action.ToString() + "," + JsonConvert.SerializeObject(result.Payload); log2.IsDataOut = false; log2.CmdNum = 0; log2.CreatedOn = DateTime.Now; log2.Msg = "first signin"; var ep2 = ((IPEndPoint)ctdata.RemoteEndPoint); log2.ClientIpPort = ep2.Address.ToString() + ":" + ep2.Port.ToString(); SaveMachineConnectionLog(log2); } //初始化client的CmdHelper instance var machine = machineSrv.GetByCustomId(ctdata.MachineCustomIdTemp); var customer = _customerService.GetByCustomerId(machine.CustomerId); ctdata.CmdHelper = new CmdHelper(customer.MachineCode1, customer.MachineCode2); } } else { //更新充電樁的心跳包接收時間 socketCommandSrv.UpdateHeartbeat(ctdata.MachineCustomId); //當 Heartbeat 與 上一個 Heartbeat相差值小於2秒,送出ChangeConfiguration.req(HeartbeatInterval: 15) 給電樁 if ((IRequest)result.Payload is HeartbeatRequest) { //var HeartbeatNow = db.MachineConnectionLog.Where(c => c.MachineCustomId == ctdata.MachineCustomId).OrderByDescending(c => c.Id).AsNoTracking().FirstOrDefault(); //if (HeartbeatNow.Data.Contains("currentTime") == true) if (ctdata.heartbeatDate != null) { DateTime currenttime = DateTime.Now; //DateTime basetime = HeartbeatNow.CreatedOn; DateTime basetime = (DateTime)ctdata.heartbeatDate; TimeSpan ts = currenttime.Subtract(basetime).Duration(); double seconddiff = ts.TotalSeconds; if ((seconddiff <= 2) && (ctdata.IsSendHeartbeatChangeConfiguration == false)) // Heartbeat 與上一個 Heartbeat時間小於 2秒 { //當 Heartbeat 與 上一個 Heartbeat相差值小於2秒,判斷是否送出ChangeConfiguration.req(HeartbeatInterval: 15) 給電樁 ctdata.IsSendHeartbeatChangeConfiguration = true; var machine = machineSrv.GetByCustomId(ctdata.MachineCustomId); //重發校時 //設定心跳時間和心跳的timeout次數 logger.Trace("set 心跳時間和心跳的timeout次數"); Cmd1001 cmd1001temp = ctdata.CmdHelper.Create(1001) as Cmd1001; cmd1001temp.Type = 1; cmd1001temp.ParamIndex = 21; cmd1001temp.ParamAmt = 2; cmd1001temp.ParamByteLength = (ushort)((ushort)cmd1001temp.ParamAmt * 4); uint p21 = (uint)machine.HeartbeatInterval; cmd1001temp.ParamByteList.AddRange(CmdUtil.ToByteArray(p21).ToList()); uint p22 = (uint)machine.HeartbeatTimeoutTimes; cmd1001temp.ParamByteList.AddRange(CmdUtil.ToByteArray(p22).ToList()); cmd1001temp.Pack(); ServerCommand sc = new ServerCommand(); sc.OutCmdNum = cmd1001temp.Cmd; sc.CreatedOn = DateTime.Now; sc.MachineId = ctdata.MachineId; sc.MachineCustomId = ctdata.MachineCustomId; sc.OutTransData = cmd1001temp.byteList.ToArray(); db.ServerCommand.Add(sc); db.SaveChanges(); } } } if (ENABLELOG_MACHINECMD) { //紀錄電樁的連線資訊 MachineConnectionLog log = new MachineConnectionLog(); log.MachineCustomId = ctdata.MachineCustomId; log.MachineId = ctdata.MachineId; log.IpPort = ctdata.LocalEndPoint.ToString(); log.IsIllegal = false; log.IsDataOut = false; log.CmdNum = 0; if (msg.Length > 2000) log.Data = msg.Substring(0, 1999); else log.Data = msg;//call.id.ToString() + "," +call.action.ToString() + "," + JsonConvert.SerializeObject(result.Payload); log.CreatedOn = DateTime.Now; if (call.action.Contains("DataTransfer")) { log.Msg = call.action + " Request(" + ((DataTransferRequest)(result.Payload)).messageId + ")"; } else log.Msg = call.action + " Request"; var ep = ((IPEndPoint)ctdata.RemoteEndPoint); log.ClientIpPort = ep.Address.ToString() + ":" + ep.Port.ToString(); SaveMachineConnectionLog(log); if (msg.Length >= 2000) // BMS封包 { MachineConnectionLog log1 = new MachineConnectionLog(); log1.MachineCustomId = ctdata.MachineCustomId; log1.MachineId = ctdata.MachineId; log1.IpPort = ctdata.LocalEndPoint.ToString(); log1.IsIllegal = false; log1.IsDataOut = false; log1.CmdNum = 0; log1.Data = "ChargingGunBMS :" + msg.Substring(2000, msg.Length - 2000); log1.CreatedOn = DateTime.Now; if (call.action.Contains("DataTransfer")) { log.Msg = call.action + " Request(" + ((DataTransferRequest)(result.Payload)).messageId + ")"; } else log.Msg = call.action + " Request"; var ep1 = ((IPEndPoint)ctdata.RemoteEndPoint); log1.ClientIpPort = ep1.Address.ToString() + ":" + ep1.Port.ToString(); SaveMachineConnectionLog(log1); } } } //將OCPP Call Message的Payload所夾帶參數資訊進行處理 var handleRequestResult = ocppMsgHandler.HandleRequest((IRequest)result.Payload, call.id, db, ref ctdata); if (handleRequestResult.Success == true) { //針對即將回傳給電樁的Confirm Message進行處理 IConfirmation conf = (IConfirmation)handleRequestResult.Payload; if (!ctdata.IsCheckIn && (conf is BootNotificationConfirmation)) { //後台接受電樁發送的BootNotification Request if (((BootNotificationConfirmation)conf).status == RegistrationStatus.Accepted) { //不存在機器,要紀錄起來 var machine = machineSrv.GetByCustomId(ctdata.MachineCustomIdTemp); ctdata.CustomerId = machine.CustomerId; ctdata.CustomerName = machine.Customer.Name; ctdata.MachineId = machine.Id; string temp = String.Empty; temp = ctdata.MachineCustomId; ctdata.MachineCustomId = ctdata.MachineCustomIdTemp; ctdata.MachineCustomIdTemp = temp; OCPP_ClientDicAdded(ctdata); //確認是否已經有新增槍數 machineSrv.CheckGunsByMachineCustomId(ctdata.MachineCustomId); uow.SaveChanges(); //設定心跳時間和心跳的timeout次數 logger.Trace("set 心跳時間和心跳的timeout次數"); Cmd1001 cmd1001 = ctdata.CmdHelper.Create(1001) as Cmd1001; cmd1001.Type = 1; cmd1001.ParamIndex = 21; cmd1001.ParamAmt = 2; cmd1001.ParamByteLength = (ushort)((ushort)cmd1001.ParamAmt * 4); uint p21 = (uint)machine.HeartbeatInterval; cmd1001.ParamByteList.AddRange(CmdUtil.ToByteArray(p21).ToList()); uint p22 = (uint)machine.HeartbeatTimeoutTimes; cmd1001.ParamByteList.AddRange(CmdUtil.ToByteArray(p22).ToList()); cmd1001.Pack(); ServerCommand sc = new ServerCommand(); sc.OutCmdNum = cmd1001.Cmd; sc.CreatedOn = DateTime.Now; sc.MachineId = ctdata.MachineId; sc.MachineCustomId = ctdata.MachineCustomId; sc.OutTransData = cmd1001.byteList.ToArray(); db.ServerCommand.Add(sc); db.SaveChanges(); //設定樁的夥伴代碼 Cmd1003 cmd1003 = ctdata.CmdHelper.Create(1003) as Cmd1003; cmd1003.ParamByteLength = 36; cmd1003.Type = 1; cmd1003.ParamIndex = 12; cmd1003.ParamByteList.AddRange(CmdUtil.ToByteArray(machine.PartnerPoleId, 36)); cmd1003.Pack(); ServerCommand sc1003 = new ServerCommand(); sc1003.OutCmdNum = cmd1003.Cmd; sc1003.CreatedOn = DateTime.Now; sc1003.MachineId = ctdata.MachineId; sc1003.MachineCustomId = ctdata.MachineCustomId; sc1003.OutTransData = cmd1003.byteList.ToArray(); db.ServerCommand.Add(sc1003); db.SaveChanges(); SendElectricityRates(machine, ctdata); //設定GetConfiguration Cmd9029 cmd9029 = ctdata.CmdHelper.Create(9029) as Cmd9029; cmd9029.SerNum = 1; cmd9029.CmdSerNum = 1; cmd9029.ParamIndex = 1; //cmd1005.ParamAmt = 2; cmd9029.ParamByteLength = (ushort)4; uint p2 = 0x55; cmd9029.ParamByteList.AddRange(CmdUtil.ToByteArray(p2)); //string type = "GetConfiguration"; //cmd1005.ParamByteList.AddRange(CmdUtil.ToByteArray(type)); cmd9029.Pack(); ServerCommand sc9029 = new ServerCommand(); sc9029.OutCmdNum = cmd9029.Cmd; sc9029.CreatedOn = DateTime.Now; sc9029.MachineId = machine.Id; sc9029.MachineCustomId = machine.CustomId; sc9029.OutTransData = cmd9029.byteList.ToArray(); db.ServerCommand.Add(sc9029); db.SaveChanges(); //后台服务器下发查询目前验证卡号名单版号 var localauthTable = db.LocalAuthorization.Where(l => l.CustomId == ctdata.MachineCustomId).FirstOrDefault(); if (localauthTable != null) //查詢電樁是否已建立 Local Authorization Table { //下發GetLocalListVersion.req logger.Trace("set CMD1011 to ServerCommand"); Cmd1011 cmd1011 = ctdata.CmdHelper.Create(1011) as Cmd1011; cmd1011.CmdSerNum = ctdata.GetCmdSerNum(); cmd1011.SerNum = ctdata.GetSerNum(); cmd1011.Pack(); ServerCommand sc1011 = new ServerCommand(); sc1011.OutCmdNum = cmd1011.Cmd; sc1011.CreatedOn = DateTime.Now; sc1011.MachineId = ctdata.MachineId; sc1011.MachineCustomId = ctdata.MachineCustomId; sc1011.OutTransData = cmd1011.byteList.ToArray(); db.ServerCommand.Add(sc1011); db.SaveChanges(); } } else if (((BootNotificationConfirmation)conf).status == RegistrationStatus.Pending) { BootNotificationPending = true; } } //回傳Confirm Message給電樁 string confirmType = string.Empty; if (call.action.Contains("DataTransfer")) { confirmType = call.action + " Confirm(" + ((DataTransferRequest)(result.Payload)).messageId + ")"; } else confirmType = call.action + " Confirm"; Send(ctdata, ocppMsgHandler.GenerateCallResult(call.id, conf), confirmType); //若BootNotification的status為Pending,後台送出 GetConfiguration Request 給電樁 if (BootNotificationPending == true) { IRequest req = MakeRequestHandler.MakeGetConfigurationRequest(); string uuid = ctdata.queue.store(req); Send(ctdata, ocppMsgHandler.GenerateCall(uuid, Actions.GetConfiguration.ToString(), req), "GetConfiguration Request"); BootNotificationPending = false; } if (handleRequestResult.Message != null) { //送 UpdateFirmware封包給電樁 if (handleRequestResult.Message.Contains("UpdateFirmware")) { //DataTransfer的下發升級指令 Send(ctdata, handleRequestResult.Message, "UpdateFirmware Request"); } //在回覆StartTransaction.conf後,下發SetChargingProfile.req if (handleRequestResult.Message.Contains("SetChargingProfile")) { //下發SetChargingProfile.req Send(ctdata, handleRequestResult.Message, "SetChargingProfile Request"); } //下發 APP 餘額/卡片餘額 if (handleRequestResult.Message.Contains("AccountBalance")) { //判斷是否為會員 if (ocppMsgHandler.IsMemberCharging((IRequest)result.Payload, db) == false) { var machine = machineSrv.GetByCustomId(ctdata.MachineCustomId); SendElectricityRates(machine, ctdata); } //下發AccountBalance.req Send(ctdata, handleRequestResult.Message, "AccountBalance Request"); } } } else { if (ENABLELOG_MACHINECMD) { //紀錄error type message MachineConnectionLog log = new MachineConnectionLog(); log.MachineCustomId = ctdata.MachineCustomId; log.MachineId = ctdata.MachineId; log.IpPort = ctdata.LocalEndPoint.ToString(); log.IsIllegal = true; log.IsDataOut = false; log.CmdNum = 0; if (msg.Length >= 2000) log.Data = msg.Substring(0, 1999); else log.Data = msg; log.CreatedOn = DateTime.Now; log.Msg = handleRequestResult.Message; var ep = ((IPEndPoint)ctdata.RemoteEndPoint); log.ClientIpPort = ep.Address.ToString() + ":" + ep.Port.ToString(); SaveMachineConnectionLog(log); if (msg.Length >= 2000) // BMS錯誤封包 { MachineConnectionLog log1 = new MachineConnectionLog(); log1.MachineCustomId = ctdata.MachineCustomId; log1.MachineId = ctdata.MachineId; log1.IpPort = ctdata.LocalEndPoint.ToString(); log1.IsIllegal = true; log1.IsDataOut = false; log1.CmdNum = 0; log1.Data = "ChargingGunBMS :" + msg.Substring(2000, msg.Length - 2000); log1.CreatedOn = DateTime.Now; log1.Msg = handleRequestResult.Message; var ep1 = ((IPEndPoint)ctdata.RemoteEndPoint); log1.ClientIpPort = ep1.Address.ToString() + ":" + ep1.Port.ToString(); SaveMachineConnectionLog(log1); } } //送出錯誤訊息給電樁 Send(ctdata, ocppMsgHandler.GenerateCallError(call.id, "NotImplemented", handleRequestResult.Message), "NotImplemented"); } } else { #region error type 處理 if (ENABLELOG_MACHINECMD) { //紀錄error type message MachineConnectionLog log = new MachineConnectionLog(); log.MachineCustomId = ctdata.MachineCustomId; log.MachineId = ctdata.MachineId; log.IpPort = ctdata.LocalEndPoint.ToString(); log.IsIllegal = true; log.IsDataOut = false; log.CmdNum = 0; log.Data = msg; log.CreatedOn = DateTime.Now; //紀錄exception, 送出錯誤訊息給電樁 if (result.Exception != null) { logger.Error(result.Exception, "OnCall error"); log.Msg = result.Exception.ToString(); } else { Send(ctdata, result.Message, "Error Message"); log.Msg = result.Message; } var ep = ((IPEndPoint)ctdata.RemoteEndPoint); log.ClientIpPort = ep.Address.ToString() + ":" + ep.Port.ToString(); SaveMachineConnectionLog(log); } #endregion error type 處理 } #endregion 處理CallMessage } } catch (SocketException e) { logger.Trace("disconnected:{0}", ctdata.MachineCustomId); RemoveClient(ctdata); return; } catch (ObjectDisposedException e) { logger.Trace("ObjectDisposedException:{0}", ctdata.MachineCustomId); //RemoveClientDic(client); return; } catch (DbEntityValidationException e) { StringBuilder sb = new StringBuilder(); foreach (var eve in e.EntityValidationErrors) { sb.AppendLine(string.Format("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:", eve.Entry.Entity.GetType().Name, eve.Entry.State)); foreach (var ve in eve.ValidationErrors) { sb.AppendLine(string.Format("- Property: \"{0}\", Error: \"{1}\"", ve.PropertyName, ve.ErrorMessage)); } } logger.Warn(e); } catch (Exception e) { logger.Warn(e); } finally { uow.Dispose(); } } } /// /// 增加電樁到ClientDic /// private void OCPP_ClientDicAdded(ClientData ctdata) { //刪除重複的機器 if (ClientDic.ContainsKey(ctdata.MachineCustomId)) { //刪除重複機器 var dupClient = ClientDic[ctdata.MachineCustomId]; RemoveClient(dupClient); } //刪掉剛連線的紀錄 lock (_lockClientDic) { if (ClientDic.ContainsKey(ctdata.MachineCustomIdTemp)) { ClientDic.Remove(ctdata.MachineCustomIdTemp); logger.Trace("delete connect record {0}", ctdata.MachineCustomId); } var oldMachineCustomId = ctdata.MachineCustomId; ctdata.MachineCustomIdTemp = ctdata.MachineCustomId; ctdata.IsCheckIn = true; logger.Trace("connect id {0} check in id {1}", oldMachineCustomId, ctdata.MachineCustomId); ClientDic.Add(ctdata.MachineCustomId, ctdata); } } /// /// 從ClientDic取出電樁 /// private void OCPP_ClientDataRemoved(ClientData ctdata) { RemoveClient(ctdata); } private void AppServer_SessionClosed(ClientData session, CloseReason reason) { logger.Trace("Enter AppServer_SessionClosed()"); lock (_lockClientDic) { ClientData client; if (!String.IsNullOrEmpty(session.Path)) { string[] words = session.Path.Split('/'); if (ClientDic.ContainsKey(words.Last())) { if (ClientDic.TryGetValue(words.Last(), out client)) { ClientDic.Remove(words.Last()); logger.Trace("RemoveClient ContainsKey" + words.Last()); client = null; } } else { if((session.MachineCustomId != null) && (session.MachineCustomIdTemp != null)) { if (ClientDic.TryGetValue(session.MachineCustomId, out client)) { ClientDic.Remove(session.MachineCustomId); logger.Trace("RemoveClient ContainsKey" + words.Last()); client = null; } else if (ClientDic.TryGetValue(session.MachineCustomIdTemp, out client)) { ClientDic.Remove(session.MachineCustomIdTemp); logger.Trace("RemoveClient ContainsKey" + words.Last()); client = null; } } } } } } private void AppServer_NewSessionConnected(ClientData client) { try { client.m_ReceiveData += new ClientData.OCPPClientDataEventHandler(ReceivedMessage); lock (_lockClientDic) { ClientDic.Add(client.MachineCustomId, client); } logger.Trace("client: " + client.MachineCustomId + " in"); using (var db = new PhihongDbContext()) { if (ENABLELOG_MACHINECMD) { // 紀錄電樁的新連線資訊 MachineConnectionLog log = new MachineConnectionLog(); log.MachineCustomId = client.MachineCustomId; log.MachineId = client.MachineId; log.IpPort = client.LocalEndPoint.ToString(); log.IsIllegal = true; log.IsDataOut = false; log.CmdNum = 0; log.CreatedOn = DateTime.Now; var ep = ((IPEndPoint)client.RemoteEndPoint); log.ClientIpPort = ep.ToString(); log.Msg = "connect"; SaveMachineConnectionLog(log); } } } catch (Exception ex) { logger.Warn(ex); RemoveClient(client); } } public void Stop() { _cts.Cancel(); var list = ClientDic.Select(c => c.Value).ToList(); foreach (var c in list) { RemoveClient(c); } } public void RemoveClient(ClientData client) { logger.Trace("RemoveClient" + client.MachineCustomId); if (client != null) { try { client.Close(CloseReason.ServerClosing); } catch (Exception ex) { //logger.Warn("Close client socket error!!"); logger.Warn(string.Format("Close client socket error!! {0} Msg:{1}", client.MachineCustomId, ex.Message)); } client.m_ReceiveData -= new ClientData.OCPPClientDataEventHandler(ReceivedMessage); client.Close(); // logger.Trace("Close client socket!!"); logger.Trace("Close client socket!!" + client.MachineCustomId); RemoveClientDic(client); logger.Trace("RemoveClient null" + client.MachineCustomId); if (client != null) { client = null; } } } public void RemoveClientDic(ClientData client) { lock (_lockClientDic) { if (ClientDic.ContainsKey(client.MachineCustomId)) { ClientDic.Remove(client.MachineCustomId); logger.Trace("RemoveClient ContainsKey" + client.MachineCustomId); } } } public void ServerCommandThread() { for (; ; ) { if (_ct.IsCancellationRequested) { break; } logger.Trace("command loop"); logger.Trace("ClientDic:" + ClientDic.Count().ToString()); logger.Trace("NeedConfirmPacketList:" + NeedConfirmPacketList.Count().ToString()); try { var redirect = ConfigurationManager.AppSettings.Get("Redirect"); if (redirect.Equals("1")) { System.Threading.Thread.Sleep(1000); continue; } using (var db = new PhihongDbContext()) { ProcessServerCommand(db); ProcessConfirmPacket(); System.Threading.Thread.Sleep(1000); //每小時發送校時 var ts = DateTime.Now - sendTiming; if (ts.TotalHours > 1) { Timing(db); sendTiming = DateTime.Now; } //每5分鐘檢查 ts = DateTime.Now - checkUpdateDt; if (ts.TotalMinutes > 5) { logger.Trace("check sw update"); CheckSW(db); logger.Trace("check fw update"); CheckFW(db); checkUpdateDt = DateTime.Now; } } } catch (Exception ex) { logger.Error("server stop"); logger.Error(ex); } } } private void ProcessServerCommand(PhihongDbContext db) { OCPPMessageHandler ocppMsgHandler = new OCPPMessageHandler(); string respone = String.Empty; string messageType = string.Empty; var machineList = ClientDic.Select(c => c.Key).ToList(); DateTime startDt = DateTime.Now.AddSeconds(-30); var commandList = db.ServerCommand.Where(c => !c.UpdatedOn.HasValue && c.CreatedOn >= startDt && c.CreatedOn <= DateTime.Now).ToList().Where(c => machineList.Contains(c.MachineCustomId)).ToList(); //處理主機傳送的有指令 var cmdMachineList = commandList.Select(c => c.MachineCustomId).Distinct().ToList(); foreach (var cmdMachine in cmdMachineList) { ClientData client; if (ClientDic.TryGetValue(cmdMachine, out client)) { //有簽到或測試指令模式 if (client.IsCheckIn) { var cmdList = commandList.Where(c => c.MachineCustomId == cmdMachine && c.OutTransData != null).ToList(); foreach (var item in cmdList) { BaseCmd c = client.CmdHelper.UpPack(item.OutTransData.ToList()); int reservationId = 0; int chargingProfileId = 0; if (c is CmdError) { continue; } if (c is Cmd1005) //Remote結束充電 { var cmd = c as Cmd1005; //Cancel預約reservationId if (cmd.ParamIndex == 10) { //槍號=> reservationID, OCPP 槍號從1 開始 reservationId = cmd.GunSerNo + 1; } } else if (c is Cmd1007) //Remote啟動充電, 如果是發送充電指令的,送一次費率過去 { var cmd = c as Cmd1007; IMachineService machineSrv = new MachineService(); var machine = machineSrv.GetByCustomId(item.MachineCustomId); SendElectricityRates(machine, client); //產生定時充電/預約 reservationId if (cmd.StartChargingType == 1 || cmd.StartChargingType == 2) { //槍號=> reservationID, OCPP 槍號從1 開始 reservationId = cmd.GunSerNo + 1; } client.CarType = Convert.ToInt32(cmd.VehicleType); } else if (c is Cmd9015) //ocpp command : SetChargingProfile { var cmd9015 = c as Cmd9015; chargingProfileId = client.GetChargingProfileId(); } respone = ocppMsgHandler.HandleServerCommand(c, client.MachineCustomId, ref client.queue, ref client.configurationKey, reservationId, chargingProfileId, out messageType, db); item.OutTransData = CmdUtil.ToByteArray(respone, respone.Length);//System.Text.UTF8Encoding.Default.GetBytes(respone);//c.byteList.ToArray(); item.UpdatedOn = DateTime.Now; db.SaveChanges(); Send(client, respone, messageType); AddConfirmPacket(client, c, respone, item.Id, messageType); respone = String.Empty; Thread.Sleep(1); } } } } } /// /// 送出指令 /// /// /// /// private bool Send(ClientData client, string ocppmessage, string messageType) { try { if (String.IsNullOrEmpty(ocppmessage) == true) return false; using (var db = new PhihongDbContext()) { if (ENABLELOG_MACHINECMD) { MachineConnectionLog log = new MachineConnectionLog(); log.MachineCustomId = client.MachineCustomId; log.MachineId = client.MachineId; log.IpPort = client.LocalEndPoint.ToString(); if (ocppmessage.Length > 2000) log.Data = ocppmessage.Substring(0, 1999); else log.Data = ocppmessage; //log.Data = ocppmessage; log.IsDataOut = true; log.CmdNum = 0; log.CreatedOn = DateTime.Now; log.Msg = messageType; var ep = ((IPEndPoint)client.RemoteEndPoint); log.ClientIpPort = ep.Address.ToString() + ":" + ep.Port.ToString(); SaveMachineConnectionLog(log); if (ocppmessage.Length >= 2000) // BMS封包 { MachineConnectionLog log1 = new MachineConnectionLog(); log1.MachineCustomId = client.MachineCustomId; log1.MachineId = client.MachineId; log1.IpPort = client.LocalEndPoint.ToString(); log1.IsIllegal = false; log1.IsDataOut = false; log1.CmdNum = 0; log1.Data = "Key :" + ocppmessage.Substring(2000, ocppmessage.Length - 2000); log1.CreatedOn = DateTime.Now; log1.Msg = messageType; var ep1 = ((IPEndPoint)client.RemoteEndPoint); log1.ClientIpPort = ep1.Address.ToString() + ":" + ep1.Port.ToString(); SaveMachineConnectionLog(log1); } } } client.Send(ocppmessage); } catch (Exception ex) { RemoveClient(client); logger.Error(ex); return false; } return true; } /// /// 判斷數據包的指令,是否需要確認 /// /// public void AddConfirmPacket(ClientData client, BaseCmd cmd, string sentmessage, int id, string messageType) { if (String.IsNullOrEmpty(sentmessage) == true) return; NeedConfirmPacket p = new NeedConfirmPacket(); var array = JsonConvert.DeserializeObject(sentmessage); p.Id = id; //p.CmdSerNum = cmd.CmdSerNum; p.SentInterval = 10; p.SentTimes = 3; p.MachineCustomId = client.MachineCustomId; p.SentMessage = sentmessage; p.SentAction = messageType; if (_needConfirmCmdList.Contains(cmd.Cmd)) { p.SentUniqueId = array[1].ToString(); lock (_lockConfirmPacketList) { NeedConfirmPacketList.Add(p); logger.Trace("Add NeedConfirmPacketList "); } } } private void Timing(PhihongDbContext db) { var list = ClientDic.Values.Where(c => c.IsCheckIn).ToList(); foreach (var item in list) { logger.Trace(item.MachineCustomId + ":sent commant timing"); Cmd1003 cmd3 = item.CmdHelper.Create(1003) as Cmd1003; cmd3.ParamByteLength = 8; cmd3.Type = 1; cmd3.ParamIndex = 2; cmd3.ParamByteList.AddRange(CmdUtil.ToByteArray(DateTime.Now)); cmd3.Pack(); ServerCommand sc2 = new ServerCommand(); sc2.OutCmdNum = cmd3.Cmd; sc2.CreatedOn = DateTime.Now; sc2.MachineId = item.MachineId; sc2.MachineCustomId = item.MachineCustomId; sc2.OutTransData = cmd3.byteList.ToArray(); db.ServerCommand.Add(sc2); db.SaveChanges(); } } /// /// 確認機器版本 /// /// private void CheckSW(PhihongDbContext db) { OCPPMessageHandler ocppMsgHandler = new OCPPMessageHandler(); string respone = String.Empty; if (ClientDic.Count() == 0) return; foreach (var item in ClientDic) { logger.Trace("check sw loop"); logger.Trace("check sw" + item.Value.MachineCustomId); var machine = db.Machine.Where(c => c.Id == item.Value.MachineId).AsNoTracking().FirstOrDefault(); if (machine == null) { logger.Error("check sw,can't find machine " + item.Value.MachineCustomId); continue; } if (machine.SW_AssignedMachineVersionId.HasValue) { logger.Trace(machine.CustomId + "asinged sw value"); var mv = db.MachineVersion.Include(c => c.PublishVersion) .Include(c => c.PublishVersion.PublishVersionFiles) .Include(c => c.PublishVersion.PublishVersionFiles.Select(z => z.UploadFile)) .Where(c => c.Id == machine.SW_AssignedMachineVersionId.Value).First(); logger.Trace(mv.Id + "get sw value"); if (!machine.SW_VersionReport.HasValue || machine.SW_VersionReport.Value != mv.PublishVersion.Version) { logger.Trace(machine.CustomId + "ready to sent commmand to update sw "); UploadFile uploadFile; //ipc 就更新清單,非ipc就更新檔案 if (mv.PublishVersion.UpdateJsonUploadFileId == null) uploadFile = mv.PublishVersion.PublishVersionFiles.First().UploadFile; else uploadFile = db.UploadFile.Find(mv.PublishVersion.UpdateJsonUploadFileId.Value); byte param = 0; //DataTransfer的下發升級指令 respone = ocppMsgHandler.HandleUpdateFirmware(ref item.Value.queue, 1, (ProgramParam)param, uploadFile); Send(item.Value, respone, "UpdateFirmware Request"); ////OCPP 的下發升級指令 //respone = String.Empty; //string fileurl = @"http://" + uploadFile.FileUrl; //respone = ocppMsgHandler.HandleOCPPUpdateFirmware(ref item.Value.queue, fileurl); //Send(item.Value, respone); logger.Trace(item.Key + ":sent command to update sw"); } } } } /// /// 確認機器版本 /// /// private void CheckFW(PhihongDbContext db) { OCPPMessageHandler ocppMsgHandler = new OCPPMessageHandler(); string respone = String.Empty; foreach (var item in ClientDic) { logger.Trace("check fw loop"); logger.Trace("check fw" + item.Value.MachineCustomId); var machine = db.Machine.Where(c => c.Id == item.Value.MachineId).AsNoTracking().FirstOrDefault(); if (machine == null) { logger.Error("check fw,can't find machine" + item.Value.MachineCustomId); continue; } if (machine.FW_AssignedMachineVersionId.HasValue) { logger.Trace(machine.CustomId + "assigned fw update value"); var mv = db.MachineVersion.Include(c => c.PublishVersion) .Include(c => c.PublishVersion.PublishVersionFiles) .Include(c => c.PublishVersion.PublishVersionFiles.Select(z => z.UploadFile)) .Where(c => c.Id == machine.FW_AssignedMachineVersionId.Value).First(); logger.Trace(mv.Id + "get fw update value"); if (!machine.FW_VersionReport.HasValue || machine.FW_VersionReport.Value != mv.PublishVersion.Version) { logger.Trace(machine.CustomId + "ready to sent command to update fw"); UploadFile uploadFile; List ufList = new List(); //ipc 就更新清單,非ipc就更新檔案 if (mv.PublishVersion.UpdateJsonUploadFileId == null) { ufList.AddRange(mv.PublishVersion.PublishVersionFiles.Select(c => c.UploadFile).ToList()); //uploadFile = mv.PublishVersion.PublishVersionFiles.First().UploadFile; } else { uploadFile = db.UploadFile.Find(mv.PublishVersion.UpdateJsonUploadFileId.Value); ufList.Add(uploadFile); } foreach (var f in ufList) { byte param = 0; if (mv.PublishVersion.UpdateJsonUploadFileId == null) { param = (byte)f.FwTagId.Value; } if (param == 28) // HMI-B2 continue; //DataTransfer的下發升級指令 respone = ocppMsgHandler.HandleUpdateFirmware(ref item.Value.queue, 2, (ProgramParam)param, f); Send(item.Value, respone, "DataTransfer Request(UpdateFirmware)"); ////OCPP 的下發升級指令 //respone = String.Empty; //string fileurl = @"http://" + f.FileUrl; //respone = ocppMsgHandler.HandleOCPPUpdateFirmware(ref item.Value.queue, fileurl); //Send(item.Value, respone); logger.Trace(item.Key + ":send command to update fw"); } } } } } /// /// 處理需確認的數據包 /// private void ProcessConfirmPacket() { List removeList = new List(); //處理需要重送的數據包 var count = NeedConfirmPacketList.Count; for (int i = 0; i < count; i++) { var item = NeedConfirmPacketList[i]; //這個要移除,不處理 if (item.SentTimes <= 0 && item.SentInterval <= 0) { removeList.Add(item); continue; } //要處理送出 if (--item.SentInterval <= 0) { ClientData client; if (ClientDic.TryGetValue(item.MachineCustomId, out client)) { //有簽到或測試指令模式 if (client.IsCheckIn) { Send(client, item.SentMessage, item.SentAction); } } //如果已經到了次數限制,3,就不再送了 if (--item.SentTimes <= 0) { item.SentTimes = 0; item.SentInterval = 0; removeList.Add(item); } else { //把間隔秒數set 3 item.SentInterval = 10; } } } //移除已經結束的數據包 lock (_lockConfirmPacketList) { foreach (var item in removeList) { NeedConfirmPacketList.Remove(item); logger.Trace("delete needConfirmPacketList MachineCustomId:{0},UUID:{1}", item.MachineCustomId, item.SentUniqueId); } } } /// /// 送出電費及服務費率 /// /// /// private void SendElectricityRates(Machine machine, ClientData client) { using (var db = new PhihongDbContext()) { if (machine.Customer.SinglePricePerKWH) { //設定每度費用 Cmd2301 cmd2301 = client.CmdHelper.Create(2301) as Cmd2301; cmd2301.CmdSerNum = client.GetCmdSerNum(); cmd2301.SerNum = client.GetSerNum(); cmd2301.PricePerKWH.RealValue = machine.PricePerKWH; cmd2301.Pack(); ServerCommand sc1 = new ServerCommand(); sc1.OutCmdNum = cmd2301.Cmd; sc1.CreatedOn = DateTime.Now; sc1.MachineId = client.MachineId; sc1.MachineCustomId = client.MachineCustomId; sc1.OutTransData = cmd2301.byteList.ToArray(); db.ServerCommand.Add(sc1); db.SaveChanges(); } else { Cmd2303 cmd2303 = client.CmdHelper.Create(2303) as Cmd2303; cmd2303.CmdSerNum = client.GetCmdSerNum(); cmd2303.SerNum = client.GetSerNum(); cmd2303.Section0000_0030.RealValue = machine.Section0000_0030; cmd2303.Section0030_0100.RealValue = machine.Section0030_0100; cmd2303.Section0100_0130.RealValue = machine.Section0100_0130; cmd2303.Section0130_0200.RealValue = machine.Section0130_0200; cmd2303.Section0200_0230.RealValue = machine.Section0200_0230; cmd2303.Section0230_0300.RealValue = machine.Section0230_0300; cmd2303.Section0300_0330.RealValue = machine.Section0300_0330; cmd2303.Section0330_0400.RealValue = machine.Section0330_0400; cmd2303.Section0400_0430.RealValue = machine.Section0400_0430; cmd2303.Section0430_0500.RealValue = machine.Section0430_0500; cmd2303.Section0500_0530.RealValue = machine.Section0500_0530; cmd2303.Section0530_0600.RealValue = machine.Section0530_0600; cmd2303.Section0600_0630.RealValue = machine.Section0600_0630; cmd2303.Section0630_0700.RealValue = machine.Section0630_0700; cmd2303.Section0700_0730.RealValue = machine.Section0700_0730; cmd2303.Section0730_0800.RealValue = machine.Section0730_0800; cmd2303.Section0800_0830.RealValue = machine.Section0800_0830; cmd2303.Section0830_0900.RealValue = machine.Section0830_0900; cmd2303.Section0900_0930.RealValue = machine.Section0900_0930; cmd2303.Section0930_1000.RealValue = machine.Section0930_1000; cmd2303.Section1000_1030.RealValue = machine.Section1000_1030; cmd2303.Section1030_1100.RealValue = machine.Section1030_1100; cmd2303.Section1100_1130.RealValue = machine.Section1100_1130; cmd2303.Section1130_1200.RealValue = machine.Section1130_1200; cmd2303.Section1200_1230.RealValue = machine.Section1200_1230; cmd2303.Section1230_1300.RealValue = machine.Section1230_1300; cmd2303.Section1300_1330.RealValue = machine.Section1300_1330; cmd2303.Section1330_1400.RealValue = machine.Section1330_1400; cmd2303.Section1400_1430.RealValue = machine.Section1400_1430; cmd2303.Section1430_1500.RealValue = machine.Section1430_1500; cmd2303.Section1500_1530.RealValue = machine.Section1500_1530; cmd2303.Section1530_1600.RealValue = machine.Section1530_1600; cmd2303.Section1600_1630.RealValue = machine.Section1600_1630; cmd2303.Section1630_1700.RealValue = machine.Section1630_1700; cmd2303.Section1700_1730.RealValue = machine.Section1700_1730; cmd2303.Section1730_1800.RealValue = machine.Section1730_1800; cmd2303.Section1800_1830.RealValue = machine.Section1800_1830; cmd2303.Section1830_1900.RealValue = machine.Section1830_1900; cmd2303.Section1900_1930.RealValue = machine.Section1900_1930; cmd2303.Section1930_2000.RealValue = machine.Section1930_2000; cmd2303.Section2000_2030.RealValue = machine.Section2000_2030; cmd2303.Section2030_2100.RealValue = machine.Section2030_2100; cmd2303.Section2100_2130.RealValue = machine.Section2100_2130; cmd2303.Section2130_2200.RealValue = machine.Section2130_2200; cmd2303.Section2200_2230.RealValue = machine.Section2200_2230; cmd2303.Section2230_2300.RealValue = machine.Section2230_2300; cmd2303.Section2300_2330.RealValue = machine.Section2300_2330; cmd2303.Section2330_2400.RealValue = machine.Section2330_2400; cmd2303.Pack(); ServerCommand sc2 = new ServerCommand(); sc2.OutCmdNum = cmd2303.Cmd; sc2.CreatedOn = DateTime.Now; sc2.MachineId = client.MachineId; sc2.MachineCustomId = client.MachineCustomId; sc2.OutTransData = cmd2303.byteList.ToArray(); db.ServerCommand.Add(sc2); db.SaveChanges(); } //設定每度服務費 Cmd2305 cmd2305 = client.CmdHelper.Create(2305) as Cmd2305; cmd2305.CmdSerNum = client.GetCmdSerNum(); cmd2305.SerNum = client.GetSerNum(); cmd2305.FeePerKWH.RealValue = machine.FeePerKWH; cmd2305.Pack(); ServerCommand sc3 = new ServerCommand(); sc3.OutCmdNum = cmd2305.Cmd; sc3.CreatedOn = DateTime.Now; sc3.MachineId = client.MachineId; sc3.MachineCustomId = client.MachineCustomId; sc3.OutTransData = cmd2305.byteList.ToArray(); db.ServerCommand.Add(sc3); db.SaveChanges(); } } private void CheckConfirmPacket(ClientData client, BaseMessage message) { lock (_lockConfirmPacketList) { logger.Trace("CheckConfirmPacket NeedConfirmPacketList:" + NeedConfirmPacketList.Count().ToString()); //檢查 Call Message/ CallResult Message / CallError Message的 UniqueId屬性, 是否與 NeedConfirmPacket的 SentUniqueId屬性 一致 var item = NeedConfirmPacketList.Where(c => c.MachineCustomId == client.MachineCustomId && c.SentUniqueId == message.id).FirstOrDefault(); if (item != null) { logger.Trace("check CheckConfirmPacket MachineCustomId:{0},SentUniqueId:{1}", item.MachineCustomId, item.SentUniqueId); using (var db = new PhihongDbContext()) { var sc = db.ServerCommand.Where(c => c.Id == item.Id).FirstOrDefault(); object payload = null; if (sc.OutCmdNum == 1001) { // 當 Heartbeat 與 上一個 Heartbeat相差值小於2秒,判斷是否送出ChangeConfiguration.req(HeartbeatInterval: 15) 給電樁 client.IsSendHeartbeatChangeConfiguration = false; } else if (sc.OutCmdNum == 9001) { sc.InCmdNum = 9002; /*9002為Cmd9002, 目前Packet Cmd沒有建立此Command*/ } else if (sc.OutCmdNum == 9003) { sc.InCmdNum = 9004; /*9004為Cmd9004, 目前Packet Cmd沒有建立此Command*/ } else if (sc.OutCmdNum == 9005) { sc.InCmdNum = 9006; /*9006為Cmd9006, 目前Packet Cmd沒有建立此Command*/ } else if (sc.OutCmdNum == 9007) { sc.InCmdNum = 9008; /*9008為Cmd9008, 目前Packet Cmd沒有建立此Command*/ } else if (sc.OutCmdNum == 9009) { sc.InCmdNum = 9010; /*9010為Cmd9010, 目前Packet Cmd沒有建立此Command*/ } else if (sc.OutCmdNum == 9011) { sc.InCmdNum = 9012; /*9012為Cmd9012, 目前Packet Cmd沒有建立此Command*/ } else if (sc.OutCmdNum == 9013) { sc.InCmdNum = 9014; /*9014為Cmd9014, 目前Packet Cmd沒有建立此Command*/ } else if (sc.OutCmdNum == 9015) { sc.InCmdNum = 9016; /*9016為Cmd9016, 目前Packet Cmd沒有建立此Command*/ } else if (sc.OutCmdNum == 9017) { sc.InCmdNum = 9018; /*9018為Cmd9018, 目前Packet Cmd沒有建立此Command*/ } else if (sc.OutCmdNum == 9019) { sc.InCmdNum = 9020; /*9020為Cmd9020, 目前Packet Cmd沒有建立此Command*/ } else if (sc.OutCmdNum == 9021) { sc.InCmdNum = 9022; /*9022為Cmd9022, 目前Packet Cmd沒有建立此Command*/ } else if (sc.OutCmdNum == 9023) { sc.InCmdNum = 9024; /*9024為Cmd9024, 目前Packet Cmd沒有建立此Command*/ } else if (sc.OutCmdNum == 9025) { sc.InCmdNum = 9026; /*9026為Cmd9026, 目前Packet Cmd沒有建立此Command*/ } else if (sc.OutCmdNum == 9027) { sc.InCmdNum = 9028; /*9028為Cmd9028, 目前Packet Cmd沒有建立此Command*/ } else if (sc.OutCmdNum == 9029) { sc.InCmdNum = 9030; /*9030為Cmd9030, 目前Packet Cmd沒有建立此Command*/ } else if (sc.OutCmdNum == 9031) { sc.InCmdNum = 9032; /*9032為Cmd9032, 目前Packet Cmd沒有建立此Command*/ } else { sc.InCmdNum = 0; } if (message is CallResultMessage) { CallResultMessage call = (CallResultMessage)message; payload = call.payload; } else if (message is CallErrorMessage) { CallErrorMessage call = (CallErrorMessage)message; payload = call.payload; } else if (message is CallMessage) { CallMessage call = (CallMessage)message; payload = call.payload; } //sc.InTransData = CmdUtil.ToByteArray(message.ToString(), message.ToString().Length);//System.Text.UTF8Encoding.Default.GetBytes(message.ToString()); sc.InTransData = CmdUtil.ToByteArray(payload.ToString(), payload.ToString().Length);//System.Text.UTF8Encoding.Default.GetBytes(message.ToString()); sc.ReceivedOn = DateTime.Now; db.SaveChanges(); item.SentInterval = 0; item.SentTimes = 0; logger.Trace("reply NeedConfirmPacket MachineCustomId:{0},SentUniqueId:{1}", item.MachineCustomId, item.SentUniqueId); } } } } private void SaveMachineConnectionLog(MachineConnectionLog log) { if (System.Configuration.ConfigurationManager.AppSettings["mongoDb"] != null) { try { MMachineConnectionLog mlog = new MMachineConnectionLog(); mlog.MachineCustomId = log.MachineCustomId; mlog.MachineId = log.MachineId; mlog.IpPort = log.IpPort; mlog.IsIllegal = log.IsIllegal; mlog.IsDataOut = log.IsDataOut; mlog.CmdNum = log.CmdNum; mlog.CreatedOn = log.CreatedOn; mlog.ClientIpPort = log.ClientIpPort; mlog.Msg = log.Msg; mlog.Data = log.Data; IMongoDatabase database = mongoService.getMongoDatabase(); var mdb = database.GetCollection(Globals._col_MachineConnectionLog); mdb.InsertOne(mlog); } catch (Exception e) { logger.Trace("mongo MachineConnectionLog error:" + e.Message); } } else { using (var db = new PhihongDbContext()) { db.MachineConnectionLog.Add(log); db.SaveChanges(); } } } } }