12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862 |
- 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<string> _cmd202lst = new List<string>();
- private List<int> _needConfirmCmdList;
- public Dictionary<string, ClientData> ClientDic { get; set; }
- public string Listening { get; set; }
- public string ApiUrl { get; set; }
- public List<NeedConfirmPacket> NeedConfirmPacketList { get; set; }
- /// <summary>
- /// 上次校時時間
- /// </summary>
- private DateTime sendTiming { get; set; }
- /// <summary>
- /// 檢查軟韌體時間
- /// </summary>
- private DateTime checkUpdateDt { get; set; }
- /// <summary>
- /// 可允許連線Clinet數
- /// </summary>
- public int connectNum { get; set; }
- /// <summary>
- /// 是否限制連線Clinet數
- /// </summary>
- public bool beConnectLimit { get; set; }
- /// <summary>
- /// 是否紀錄與充電樁互傳命令 在 MachineConnectionLog
- /// </summary>
- private bool ENABLELOG_MACHINECMD = false;
- public WSServer()
- {
- using (var db = new PhihongDbContext())
- {
- _ct = _cts.Token;
- ClientDic = new Dictionary<string, ClientData>();
- NeedConfirmPacketList = new List<NeedConfirmPacket>();
- //需要確認回傳的指令
- _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<IListenerConfig> llistener = new List<IListenerConfig>();
- 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<IListenerConfig> 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;
- }
- }
- }
- /// <summary>
- /// 處理電樁送的OCPP 訊息
- /// </summary>
- 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();
- }
- }
- }
- /// <summary>
- /// 增加電樁到ClientDic
- /// </summary>
- 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);
- }
- }
- /// <summary>
- /// 從ClientDic取出電樁
- /// </summary>
- 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<ClientData, String>(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<ClientData, String>(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);
- }
- }
- }
- }
- }
- /// <summary>
- /// 送出指令
- /// </summary>
- /// <param name="client"></param>
- /// <param name="cmd"></param>
- /// <returns></returns>
- 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;
- }
- /// <summary>
- /// 判斷數據包的指令,是否需要確認
- /// </summary>
- /// <param name="cmd"></param>
- 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<JArray>(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();
- }
- }
- /// <summary>
- /// 確認機器版本
- /// </summary>
- /// <param name="db"></param>
- 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");
- }
- }
- }
- }
- /// <summary>
- /// 確認機器版本
- /// </summary>
- /// <param name="db"></param>
- 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<UploadFile> ufList = new List<UploadFile>();
- //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");
- }
- }
- }
- }
- }
- /// <summary>
- /// 處理需確認的數據包
- /// </summary>
- private void ProcessConfirmPacket()
- {
- List<NeedConfirmPacket> removeList = new List<NeedConfirmPacket>();
- //處理需要重送的數據包
- 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);
- }
- }
- }
- /// <summary>
- /// 送出電費及服務費率
- /// </summary>
- /// <param name="machine"></param>
- /// <param name="client"></param>
- 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<MMachineConnectionLog>(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();
- }
-
- }
- }
- }
- }
|