ProtalServer.cs 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116
  1. using NLog;
  2. using OCPPServer.Protocol;
  3. using OCPPServer.SubProtocol;
  4. using SuperSocket.SocketBase;
  5. using SuperSocket.SocketBase.Config;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.IO;
  9. using System.Linq;
  10. using System.Text;
  11. using System.Xml.Linq;
  12. using EVCB_OCPP.Packet.Messages.Basic;
  13. using EVCB_OCPP.Packet.Messages.Core;
  14. using EVCB_OCPP.WSServer.Message;
  15. using EVCB_OCPP.Packet.Messages;
  16. using EVCB_OCPP.Domain;
  17. using EVCB_OCPP.Domain.Models.Database;
  18. using System.Threading;
  19. using System.Data.Entity;
  20. using EVCB_OCPP.Packet.Features;
  21. using EVCB_OCPP.Packet.Features.Core;
  22. using Newtonsoft.Json;
  23. using OCPPPackage.Profiles;
  24. using System.Threading.Tasks;
  25. using EVCB_OCPP.WSServer.Helper;
  26. using System.Data.SqlClient;
  27. using EVCB_OCPP.Packet.Messages.FirmwareManagement;
  28. using EVCB_OCPP.Packet.Messages.RemoteTrigger;
  29. using System.Configuration;
  30. using System.Net;
  31. using System.Net.Security;
  32. using System.Security.Cryptography.X509Certificates;
  33. namespace EVCB_OCPP.WSServer
  34. {
  35. internal class ProtalServer
  36. {
  37. static private ILogger logger = NLog.LogManager.GetCurrentClassLogger();
  38. private Dictionary<string, ClientData> clientDic = new Dictionary<string, ClientData>();
  39. private readonly Object _lockClientDic = new object();
  40. private readonly Object _lockConfirmPacketList = new object();
  41. private ProfileHandler profileHandler = new ProfileHandler();
  42. private List<NeedConfirmMessage> needConfirmPacketList = new List<NeedConfirmMessage>();
  43. private DateTime checkUpdateDt = DateTime.Now;
  44. private List<string> needConfirmActions = new List<string>()
  45. {
  46. "GetConfiguration",
  47. "ChangeConfiguration",
  48. "RemoteStartTransaction",
  49. "RemoteStopTransaction",
  50. "ChangeAvailability",
  51. "ClearCache",
  52. "DataTransfer",
  53. "Reset",
  54. "UnlockConnector",
  55. "TriggerMessage",
  56. "GetDiagnostics",
  57. "UpdateFirmware",
  58. "GetLocalListVersion",
  59. "SendLocalList",
  60. "SetChargingProfile",
  61. "ClearChargingProfile",
  62. "GetCompositeSchedule",
  63. "ReserveNow",
  64. "CancelReservation",
  65. };
  66. private List<Profile> profiles = new List<Profile>()
  67. {
  68. new CoreProfile(),
  69. new FirmwareManagementProfile(),
  70. new ReservationProfile(),
  71. new RemoteTriggerProfile(),
  72. new SmartChargingProfile(),
  73. new LocalAuthListManagementProfile()
  74. };
  75. private CancellationTokenSource _cts = new CancellationTokenSource();
  76. private CancellationToken _ct;
  77. internal ProtalServer()
  78. {
  79. _ct = _cts.Token;
  80. WarmUpLog();
  81. }
  82. internal void Start()
  83. {
  84. if (!GlobalConfig.LoadAPPConfig())
  85. {
  86. Console.WriteLine("Please check App.Config setting .");
  87. return;
  88. }
  89. OpenNetwork();
  90. Task serverCommandTask = new Task(ServerMessageTrigger, _ct);
  91. serverCommandTask.Start();
  92. Task serverUpdateTask = new Task(ServerUpdateTrigger, _ct);
  93. serverUpdateTask.Start();
  94. Task serverHealthTask = new Task(HealthAlarmTrigger, _ct);
  95. // serverHealthTask.Start();
  96. while (true)
  97. {
  98. var input = Console.ReadLine();
  99. switch (input.ToLower())
  100. {
  101. case "stop":
  102. logger.Info("Command stop");
  103. Stop();
  104. break;
  105. case "gc":
  106. logger.Info("Command GC");
  107. GC.Collect();
  108. break;
  109. case "lc":
  110. {
  111. logger.Info("Command List Clients");
  112. Dictionary<string, ClientData> _copyClientDic = null;
  113. lock (_lockClientDic)
  114. {
  115. _copyClientDic = new Dictionary<string, ClientData>(clientDic);
  116. }
  117. var list = _copyClientDic.Select(c => c.Value).ToList();
  118. int i = 1;
  119. foreach (var c in list)
  120. {
  121. logger.Info(i + ":" + c.ChargeBoxId + " " + c.SessionID);
  122. i++;
  123. }
  124. }
  125. break;
  126. case "lcn":
  127. {
  128. logger.Info("Command List Customer Name");
  129. Dictionary<string, ClientData> _copyClientDic = null;
  130. lock (_lockClientDic)
  131. {
  132. _copyClientDic = new Dictionary<string, ClientData>(clientDic);
  133. }
  134. var lcn = clientDic.Select(c => c.Value.CustomerName).Distinct().ToList();
  135. int iLcn = 1;
  136. foreach (var c in lcn)
  137. {
  138. logger.Info(iLcn + ":" + c + ":" + clientDic.Where(z => z.Value.CustomerName == c).Count().ToString());
  139. iLcn++;
  140. }
  141. }
  142. break;
  143. case "help":
  144. logger.Info("Command help!!");
  145. logger.Info("lcn : List Customer Name");
  146. logger.Info("gc : GC Collect");
  147. logger.Info("lc : List Clients");
  148. logger.Info("cls : clear console");
  149. logger.Info("silent : silent");
  150. logger.Info("show : show log");
  151. // logger.Info("rcl : show Real Connection Limit");
  152. break;
  153. case "cls":
  154. logger.Info("Command clear");
  155. Console.Clear();
  156. break;
  157. case "silent":
  158. logger.Info("Command silent");
  159. var xe = XElement.Load("NLog.config");
  160. var xns = xe.GetDefaultNamespace();
  161. var minlevelattr = xe.Descendants(xns + "rules").Elements(xns + "logger")
  162. .Where(c => c.Attribute("writeTo").Value.Equals("console")).Attributes("minlevel").FirstOrDefault();
  163. if (minlevelattr != null)
  164. {
  165. minlevelattr.Value = "info";
  166. }
  167. xe.Save("NLog.config");
  168. break;
  169. case "show":
  170. logger.Info("Command show");
  171. var xe1 = XElement.Load("NLog.config");
  172. var xns1 = xe1.GetDefaultNamespace();
  173. var minlevelattr1 = xe1.Descendants(xns1 + "rules").Elements(xns1 + "logger")
  174. .Where(c => c.Attribute("writeTo").Value.Equals("console")).Attributes("minlevel").FirstOrDefault();
  175. if (minlevelattr1 != null)
  176. {
  177. minlevelattr1.Value = "trace";
  178. }
  179. xe1.Save("NLog.config");
  180. break;
  181. case "rcl":
  182. break;
  183. default:
  184. break;
  185. }
  186. }
  187. }
  188. internal void Stop()
  189. {
  190. if (_cts != null)
  191. {
  192. _cts.Cancel();
  193. }
  194. }
  195. private void CheckEVSEConfigure(string chargeBoxId)
  196. {
  197. int skipCount = 0;
  198. int takeCount = 8;
  199. using (var db = new MainDBContext())
  200. {
  201. string maxKeys = StandardConfiguration.AllConfigs.Skip(skipCount).Take(1).FirstOrDefault();
  202. if (maxKeys == StandardConfiguration.GetConfigurationMaxKeys)
  203. {
  204. var _Configure = db.MachineConfigure.Where(x => x.ChargeBoxId == chargeBoxId && x.ConfigureName == maxKeys).Select(x => new { ConfigureSetting = x.ConfigureSetting, ConfigureName = x.ConfigureName }).FirstOrDefault();
  205. if (_Configure != null)
  206. {
  207. int cp_ConfiureCount = 0;
  208. int.TryParse(_Configure.ConfigureSetting, out cp_ConfiureCount);
  209. takeCount = takeCount > cp_ConfiureCount ? cp_ConfiureCount : takeCount;
  210. skipCount = 1;
  211. if (string.IsNullOrEmpty(_Configure.ConfigureSetting)) return;
  212. }
  213. }
  214. while (StandardConfiguration.AllConfigs.Count > skipCount)
  215. {
  216. string _key = StandardConfiguration.AllConfigs.Skip(skipCount).Take(1).FirstOrDefault();
  217. var _Configure = db.MachineConfigure.Where(x => x.ChargeBoxId == chargeBoxId && x.ConfigureName == _key).Select(x => new { ConfigureSetting = x.ConfigureSetting, ConfigureName = x.ConfigureName }).FirstOrDefault();
  218. takeCount = StandardConfiguration.AllConfigs.Count - skipCount > takeCount ? takeCount : StandardConfiguration.AllConfigs.Count - skipCount;
  219. var _keys = StandardConfiguration.AllConfigs.Skip(skipCount).Take(takeCount).ToList();
  220. // Console.WriteLine("===============Skip:" + skipCount);
  221. if (_Configure == null)
  222. {
  223. // Console.WriteLine("_Configure == null===============Skip:" + skipCount);
  224. db.ServerMessage.Add(new ServerMessage()
  225. {
  226. ChargeBoxId = chargeBoxId,
  227. CreatedBy = "Server",
  228. CreatedOn = DateTime.Now,
  229. OutAction = Actions.GetConfiguration.ToString(),
  230. OutRequest = JsonConvert.SerializeObject(
  231. new GetConfigurationRequest()
  232. {
  233. key = _keys
  234. },
  235. new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
  236. SerialNo = Guid.NewGuid().ToString(),
  237. InMessage = string.Empty
  238. });
  239. db.SaveChanges();
  240. }
  241. skipCount = skipCount + takeCount;
  242. }
  243. }
  244. }
  245. private void OpenNetwork()
  246. {
  247. //載入OCPP Protocol
  248. var appServer = new OCPPWSServer(new List<OCPPSubProtocol>() { new OCPPSubProtocol(), new OCPPSubProtocol(" ocpp1.6") });
  249. List<IListenerConfig> llistener = new List<IListenerConfig>();
  250. //System.Net.IPAddress.Any.ToString()
  251. // llistener.Add(new ListenerConfig { Ip = "", Port = Convert.ToInt32(wssserverPort), Backlog = 100, Security = serverSecurity });
  252. llistener.Add(new ListenerConfig { Ip = System.Net.IPAddress.Any.ToString(), Port = Convert.ToInt32(GlobalConfig.GetWS_Port()), Backlog = 100, Security = "None" });
  253. llistener.Add(new ListenerConfig { Ip = System.Net.IPAddress.Any.ToString(), Port = Convert.ToInt32(GlobalConfig.GetWSS_Port()), Backlog = 100, Security = "tls" });
  254. var config = ConfigurationManager.GetSection("superSocket") as IConfigurationSource;
  255. ICertificateConfig Certificate = config.Servers.ElementAt(0).Certificate;
  256. IEnumerable<IListenerConfig> listeners = llistener;
  257. //設定server config
  258. var serverConfig = new ServerConfig
  259. {
  260. //Port = Convert.ToInt32(2012),
  261. //Ip = "172.17.40.13",
  262. MaxRequestLength = 4096,
  263. //Security = serverSecurity,
  264. Certificate = Certificate,
  265. Listeners = listeners,
  266. };
  267. //Setup with listening port
  268. if (!appServer.Setup(serverConfig, logFactory: new OCPPLogFactory()))
  269. {
  270. Console.WriteLine("Failed to setup!");
  271. return;
  272. }
  273. appServer.NewSessionConnected += AppServer_NewSessionConnected;
  274. appServer.SessionClosed += AppServer_SessionClosed;
  275. //Try to start the appServer
  276. if (!appServer.Start())
  277. {
  278. Console.WriteLine("Failed to start!");
  279. Console.ReadKey();
  280. return;
  281. }
  282. }
  283. private void AppServer_SessionClosed(ClientData session, CloseReason value)
  284. {
  285. // Console.WriteLine(session.RemoteEndPoint.Address);
  286. WriteMachineLog(session, string.Format("CloseReason: {0}", value), "Connection", "");
  287. RemoveClient(session);
  288. // close Connection
  289. }
  290. private void AppServer_NewSessionConnected(ClientData session)
  291. {
  292. try
  293. {
  294. lock (_lockClientDic)
  295. {
  296. bool isNotSupported = session.SecWebSocketProtocol.Contains("ocpp1.6") ? false : true;
  297. if (isNotSupported)
  298. {
  299. logger.Debug(string.Format("ChargeBoxId:{0} SecWebSocketProtocol:{1} NotSupported", session.ChargeBoxId, session.SecWebSocketProtocol));
  300. WriteMachineLog(session, string.Format("SecWebSocketProtocol:{0} NotSupported", session.SecWebSocketProtocol), "Connection", "");
  301. return;
  302. }
  303. ClientData _removeClient = null;
  304. clientDic.TryGetValue(session.ChargeBoxId, out _removeClient);
  305. if (_removeClient != null)
  306. {
  307. WriteMachineLog(_removeClient, "Duplicate Logins", "Connection", "");
  308. _removeClient.Close(CloseReason.ServerShutdown);
  309. RemoveClient(_removeClient);
  310. }
  311. session.IsCheckIn = true;
  312. clientDic.Add(session.ChargeBoxId, session);
  313. session.m_ReceiveData += new ClientData.OCPPClientDataEventHandler<ClientData, String>(ReceivedMessage);
  314. logger.Debug("------------New " + (session == null ? "Oops" : session.ChargeBoxId));
  315. WriteMachineLog(session, "NewSessionConnected", "Connection", "");
  316. using (var db = new MainDBContext())
  317. {
  318. var machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault();
  319. if (machine != null)
  320. {
  321. machine.ConnectionType = session.Origin.Contains("https") ? 2 : 1;
  322. db.SaveChanges();
  323. }
  324. }
  325. CheckEVSEConfigure(session.ChargeBoxId);
  326. }
  327. }
  328. catch (Exception ex)
  329. {
  330. logger.Error(string.Format("NewSessionConnected Ex: {0}", ex.ToString()));
  331. }
  332. }
  333. private void ReceivedMessage(ClientData session, string rawdata)
  334. {
  335. BasicMessageHandler msgAnalyser = new BasicMessageHandler();
  336. MessageResult analysisResult = msgAnalyser.AnalysisReceiveData(session, rawdata);
  337. WriteMachineLog(session, rawdata,
  338. string.Format("{0} {1}", string.IsNullOrEmpty(analysisResult.Action) ? "unknown" : analysisResult.Action, analysisResult.Id == 2 ? "Request" : (analysisResult.Id == 3 ? "Confirmation" : "Error")), string.IsNullOrEmpty(analysisResult.CallErrorMsg) ? "" : analysisResult.Exception.Message);
  339. if (!analysisResult.Success)
  340. {
  341. //解析RawData就發生錯誤
  342. if (!string.IsNullOrEmpty(analysisResult.CallErrorMsg))
  343. {
  344. Send(session, analysisResult.CallErrorMsg, string.Format("{0} {1}", analysisResult.Action, "Error"));
  345. }
  346. else
  347. {
  348. BaseMessage _baseMsg = analysisResult.Message as BaseMessage;
  349. string replyMsg = msgAnalyser.GenerateCallError(_baseMsg.Id, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
  350. string errorMsg = string.Empty;
  351. if (analysisResult.Exception != null)
  352. {
  353. errorMsg = analysisResult.Exception.ToString();
  354. }
  355. Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
  356. }
  357. }
  358. else
  359. {
  360. Actions action = Convertor.GetAction(analysisResult.Action);
  361. switch (analysisResult.Id)
  362. {
  363. case BasicMessageHandler.TYPENUMBER_CALL:
  364. {
  365. ProcessRequestMessage(analysisResult, session, action);
  366. }
  367. break;
  368. case BasicMessageHandler.TYPENUMBER_CALLRESULT:
  369. {
  370. ProcessConfirmationMessage(analysisResult, session, action);
  371. }
  372. break;
  373. case BasicMessageHandler.TYPENUMBER_CALLERROR:
  374. {
  375. //只處理 丟出Request 收到Error的訊息
  376. if (analysisResult.Success)
  377. {
  378. ProcessErrorMessage(analysisResult, session, action);
  379. }
  380. }
  381. break;
  382. default:
  383. {
  384. logger.Error(string.Format("Can't analyze messagetype:{0} of raw data :{1} by {2}", analysisResult.Id, rawdata, session.ChargeBoxId));
  385. }
  386. break;
  387. }
  388. }
  389. }
  390. private void ProcessRequestMessage(MessageResult analysisResult, ClientData session, Actions action)
  391. {
  392. BasicMessageHandler msgAnalyser = new BasicMessageHandler();
  393. if (!session.IsCheckIn && action != Actions.BootNotification)
  394. {
  395. string response = msgAnalyser.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.GenericError, OCPPErrorDescription.NotChecked);
  396. Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Error"));
  397. }
  398. else
  399. {
  400. var profileName = profiles.Where(x => x.IsExisted(analysisResult.Action)).Select(x => x.Name).FirstOrDefault();
  401. switch (profileName)
  402. {
  403. case "Core":
  404. {
  405. bool oldstatus = session.IsCheckIn;
  406. var replyResult = profileHandler.ExecuteCoreRequest(action, session, (IRequest)analysisResult.Message);
  407. if (replyResult.Success)
  408. {
  409. string response = msgAnalyser.GenerateConfirmation(analysisResult.UUID, (IConfirmation)replyResult.Message);
  410. Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Confirmation"));
  411. if (action == Actions.BootNotification && replyResult.Message is BootNotificationConfirmation)
  412. {
  413. if (((BootNotificationConfirmation)replyResult.Message).status == Packet.Messages.SubTypes.RegistrationStatus.Accepted)
  414. {
  415. session.IsCheckIn = true;
  416. if (!oldstatus)
  417. {
  418. using (var db = new MainDBContext())
  419. {
  420. var machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault();
  421. if (machine != null)
  422. {
  423. machine.ConnectionType = session.Origin.Contains("https") ? 2 : 1;
  424. db.SaveChanges();
  425. }
  426. }
  427. // CheckEVSEConfigure(session.ChargeBoxId);
  428. }
  429. }
  430. }
  431. }
  432. else
  433. {
  434. string response = msgAnalyser.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
  435. string errorMsg = replyResult.Exception != null ? replyResult.Exception.ToString() : string.Empty;
  436. Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
  437. }
  438. }
  439. break;
  440. case "FirmwareManagement":
  441. {
  442. var replyResult = profileHandler.ExecuteFirmwareManagementRequest(action, session, (IRequest)analysisResult.Message);
  443. if (replyResult.Success)
  444. {
  445. string response = msgAnalyser.GenerateConfirmation(analysisResult.UUID, (IConfirmation)replyResult.Message);
  446. Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Confirmation"));
  447. }
  448. else
  449. {
  450. string response = msgAnalyser.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
  451. string errorMsg = replyResult.Exception != null ? replyResult.Exception.ToString() : string.Empty;
  452. Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
  453. }
  454. }
  455. break;
  456. default:
  457. {
  458. string replyMsg = msgAnalyser.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
  459. string errorMsg = string.Format("Couldn't find action name: {0} of profile", action);
  460. Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
  461. }
  462. break;
  463. }
  464. }
  465. }
  466. private void ProcessConfirmationMessage(MessageResult analysisResult, ClientData session, Actions action)
  467. {
  468. BasicMessageHandler msgAnalyser = new BasicMessageHandler();
  469. if (ReConfirmMessage(analysisResult))
  470. {
  471. var profileName = profiles.Where(x => x.IsExisted(analysisResult.Action)).Select(x => x.Name).FirstOrDefault();
  472. MessageResult confirmResult = null;
  473. switch (profileName)
  474. {
  475. case "Core":
  476. {
  477. confirmResult = profileHandler.ExecuteCoreConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
  478. }
  479. break;
  480. case "FirmwareManagement":
  481. {
  482. confirmResult = profileHandler.ExecuteFirmwareManagementConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
  483. }
  484. break;
  485. case "RemoteTrigger":
  486. {
  487. confirmResult = profileHandler.ExecuteRemoteTriggerConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
  488. }
  489. break;
  490. case "Reservation":
  491. {
  492. confirmResult = profileHandler.ExecuteReservationConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
  493. }
  494. break;
  495. case "LocalAuthListManagement":
  496. {
  497. confirmResult = profileHandler.ExecuteLocalAuthListManagementConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
  498. }
  499. break;
  500. case "SmartCharging":
  501. {
  502. confirmResult = profileHandler.ExecuteSmartChargingConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
  503. }
  504. break;
  505. default:
  506. {
  507. string replyMsg = msgAnalyser.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
  508. string errorMsg = string.Format("Couldn't find action name: {0} of profile", action);
  509. Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
  510. }
  511. break;
  512. }
  513. if (confirmResult == null || !confirmResult.Success)
  514. {
  515. logger.Error(string.Format("Action:{0} MessageId:{1} ExecuteConfirm Error:{2} ",
  516. analysisResult.Action, analysisResult.UUID, confirmResult.Exception.ToString()));
  517. }
  518. }
  519. else
  520. {
  521. string replyMsg = msgAnalyser.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
  522. string errorMsg = string.Format("Action:{0} MessageId:{1} didn't exist in confirm message", analysisResult.Action, analysisResult.UUID);
  523. Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
  524. }
  525. }
  526. private void ProcessErrorMessage(MessageResult analysisResult, ClientData session, Actions action)
  527. {
  528. BasicMessageHandler msgAnalyser = new BasicMessageHandler();
  529. if (ReConfirmMessage(analysisResult))
  530. {
  531. var profileName = profiles.Where(x => x.IsExisted(analysisResult.Action)).Select(x => x.Name).FirstOrDefault();
  532. switch (profileName)
  533. {
  534. case "Core":
  535. {
  536. profileHandler.ReceivedCoreError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId);
  537. }
  538. break;
  539. case "FirmwareManagement":
  540. {
  541. profileHandler.ReceivedFirmwareManagementError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId);
  542. }
  543. break;
  544. case "RemoteTrigger":
  545. {
  546. profileHandler.ReceivedRemoteTriggerError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId);
  547. }
  548. break;
  549. case "Reservation":
  550. {
  551. profileHandler.ExecuteReservationError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId);
  552. }
  553. break;
  554. case "LocalAuthListManagement":
  555. {
  556. profileHandler.ReceivedLocalAuthListManagementError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId);
  557. }
  558. break;
  559. case "SmartCharging":
  560. {
  561. profileHandler.ReceivedSmartChargingError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId);
  562. }
  563. break;
  564. default:
  565. {
  566. string replyMsg = msgAnalyser.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
  567. string errorMsg = string.Format("Couldn't find action name: {0} of profile", action);
  568. Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
  569. }
  570. break;
  571. }
  572. }
  573. else
  574. {
  575. string replyMsg = msgAnalyser.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
  576. string errorMsg = string.Format("Action:{0} MessageId:{1} didn't exist in confirm message", analysisResult.Action, analysisResult.UUID);
  577. Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
  578. }
  579. }
  580. private void Send(ClientData session, string msg, string messageType, string errorMsg = "")
  581. {
  582. try
  583. {
  584. if (session != null)
  585. {
  586. WriteMachineLog(session, msg, messageType, errorMsg, true);
  587. session.Send(msg);
  588. }
  589. }
  590. catch (Exception ex)
  591. {
  592. logger.Error(string.Format("Send Ex:{0}", ex.ToString()));
  593. }
  594. }
  595. async private void ServerUpdateTrigger()
  596. {
  597. for (; ; )
  598. {
  599. if (_ct.IsCancellationRequested)
  600. {
  601. break;
  602. }
  603. var min_Interval = (DateTime.Now - checkUpdateDt).TotalMinutes;
  604. if (min_Interval > 3)
  605. {
  606. BasicMessageHandler msgAnalyser = new BasicMessageHandler();
  607. Dictionary<string, ClientData> _copyClientDic = null;
  608. lock (_lockClientDic)
  609. {
  610. _copyClientDic = new Dictionary<string, ClientData>(clientDic);
  611. }
  612. checkUpdateDt = DateTime.Now;
  613. using (var db = new MainDBContext())
  614. {
  615. //var needUpdateChargers = db.Machine.Where(x => x.FW_AssignedMachineVersionId.HasValue == true &&
  616. // x.FW_AssignedMachineVersionId != x.FW_VersionReport && x.Online == true)
  617. // .Select(x => new { x.Id, x.ChargeBoxId, x.FW_AssignedMachineVersionId }).ToList();
  618. var needUpdateChargers = db.Machine.Where(x => x.FW_AssignedMachineVersionId.HasValue == true &&
  619. x.FW_AssignedMachineVersionId != x.FW_VersionReport && x.Online == true)
  620. .Select(x => x.ChargeBoxId).AsNoTracking().ToList();
  621. foreach (var chargeBoxId in needUpdateChargers)
  622. {
  623. try
  624. {
  625. ClientData session;
  626. if (_copyClientDic.TryGetValue(chargeBoxId, out session))
  627. {
  628. string requestId = Guid.NewGuid().ToString();
  629. // using (var db = new MainDBContext())
  630. if (session.IsCheckIn)
  631. {
  632. var _request = new TriggerMessageRequest()
  633. {
  634. requestedMessage = Packet.Messages.SubTypes.MessageTrigger.FirmwareStatusNotification
  635. };
  636. var uuid = session.queue.store(_request);
  637. string rawRequest = msgAnalyser.GenerateRequest(uuid, _request.Action, _request);
  638. Send(session, rawRequest, string.Format("{0} {1}", _request.Action, "Request"), "");
  639. #region OCTT ,測試韌體更新方式
  640. //--------------------> OCTT ,測試韌體更新方式
  641. //{
  642. // var machine = db.Machine.Where(x => x.FW_AssignedMachineVersionId.HasValue == true &&
  643. // x.FW_AssignedMachineVersionId != x.FW_VersionReport && x.ChargeBoxId == session.ChargeBoxId)
  644. // .Select(x => new { x.Id, x.FW_AssignedMachineVersionId }).FirstOrDefault();
  645. // if (machine != null)
  646. // {
  647. // var mv = db.MachineVersion.Include(c => c.PublishVersion)
  648. // .Include(c => c.PublishVersion.PublishVersionFiles)
  649. // .Include(c => c.PublishVersion.PublishVersionFiles.Select(z => z.UploadFile))
  650. // .Where(c => c.Id == machine.FW_AssignedMachineVersionId.Value).First();
  651. // string downloadUrl = mv.PublishVersion.PublishVersionFiles.FirstOrDefault().UploadFile.FileUrl;
  652. // var _updateFWrequest = new UpdateFirmwareRequest()
  653. // {
  654. // location = new Uri(downloadUrl),
  655. // retries = 3,
  656. // retrieveDate = DateTime.Now,
  657. // retryInterval = 10
  658. // };
  659. // db.MachineOperateRecord.Add(new MachineOperateRecord()
  660. // {
  661. // CreatedOn = DateTime.Now,
  662. // ChargeBoxId = session.ChargeBoxId,
  663. // SerialNo = requestId,
  664. // RequestContent = JsonConvert.SerializeObject(_updateFWrequest, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
  665. // EVSE_Status = 0,
  666. // EVSE_Value = "Fw Version:" + machine.FW_AssignedMachineVersionId,
  667. // Status = 0,
  668. // RequestType = 0,
  669. // });
  670. // db.ServerMessage.Add(new ServerMessage()
  671. // {
  672. // ChargeBoxId = session.ChargeBoxId,
  673. // CreatedBy = "Server",
  674. // CreatedOn = DateTime.Now,
  675. // OutAction = _updateFWrequest.Action.ToString(),
  676. // OutRequest = JsonConvert.SerializeObject(_updateFWrequest, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
  677. // SerialNo = requestId,
  678. // InMessage = string.Empty
  679. // });
  680. // db.SaveChanges();
  681. // }
  682. //}
  683. #endregion
  684. }
  685. }
  686. }
  687. catch (Exception ex)
  688. {
  689. logger.Error(string.Format("serverUpdateTrigger ChargeBoxId:{0} Ex:{1}", chargeBoxId, ex.ToString()));
  690. }
  691. }
  692. }
  693. await Task.Delay(1000);
  694. // Thread.CurrentThread.Join(1000);
  695. }
  696. }
  697. }
  698. async private void ServerMessageTrigger()
  699. {
  700. for (; ; )
  701. {
  702. if (_ct.IsCancellationRequested)
  703. {
  704. break;
  705. }
  706. try
  707. {
  708. RemoveConfirmMessage();
  709. BasicMessageHandler msgAnalyser = new BasicMessageHandler();
  710. using (var db = new MainDBContext())
  711. {
  712. DateTime startDt = DateTime.Now.AddSeconds(-30);
  713. DateTime dt = new DateTime(1991, 1, 1);
  714. //Console.WriteLine(string.Format("{0} IN", DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
  715. var commandList = db.ServerMessage.Where(c => c.ReceivedOn == dt && c.UpdatedOn == dt && c.CreatedOn >= startDt && c.CreatedOn <= DateTime.Now).AsNoTracking().ToList();
  716. //處理主機傳送的有指令
  717. var cmdMachineList = commandList.Select(c => c.ChargeBoxId).Distinct().ToList();
  718. if (commandList.Count > 0)
  719. {
  720. Console.WriteLine(string.Format("Now:{0} commandList Count:{1} ", DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"), commandList.Count));
  721. }
  722. foreach (var charger_SN in cmdMachineList)
  723. {
  724. ClientData session;
  725. string uuid = string.Empty;
  726. if (clientDic.TryGetValue(charger_SN, out session))
  727. {
  728. Console.WriteLine(string.Format("charger_SN:{0} startDt:{1} CreatedOn:{2}", charger_SN, startDt.ToString("yyyy/MM/dd HH:mm:ss"), DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
  729. if (session.IsCheckIn)
  730. {
  731. var cmdList = commandList.Where(c => c.ChargeBoxId == charger_SN).ToList();
  732. foreach (var item in cmdList)
  733. {
  734. IRequest request = null;
  735. Actions action = Actions.None;
  736. Enum.TryParse(item.OutAction, out action);
  737. Type _RequestType = null;
  738. for (int i = 0; i < profiles.Count; i++)
  739. {
  740. var feature = profiles[i].GetFeaturebyAction(item.OutAction);
  741. if (feature != null)
  742. {
  743. _RequestType = feature.GetRequestType();
  744. break;
  745. }
  746. }
  747. if (_RequestType != null)
  748. {
  749. request = JsonConvert.DeserializeObject(item.OutRequest, _RequestType) as IRequest;
  750. uuid = session.queue.store(request);
  751. string rawRequest = msgAnalyser.GenerateRequest(uuid, item.OutAction, request);
  752. Send(session, rawRequest, string.Format("{0} {1}", action, "Request"), "");
  753. }
  754. AddConfirmMessage(charger_SN, item.Id, item.SerialNo, item.OutAction, uuid);
  755. #region 更新資料表單一欄位
  756. var _UpdatedItem = new ServerMessage() { Id = item.Id, UpdatedOn = DateTime.Now };
  757. db.Configuration.AutoDetectChangesEnabled = false;//自動呼叫DetectChanges()比對所有的entry集合的每一個屬性Properties的新舊值
  758. db.Configuration.ValidateOnSaveEnabled = false;// 因為Entity有些欄位必填,若不避開會有Validate錯誤
  759. // var _UpdatedItem = db.ServerMessage.Where(x => x.Id == item.Id).FirstOrDefault();
  760. db.ServerMessage.Attach(_UpdatedItem);
  761. _UpdatedItem.UpdatedOn = DateTime.Now;
  762. db.Entry(_UpdatedItem).Property(x => x.UpdatedOn).IsModified = true;// 可以直接使用這方式強制某欄位要更新,只是查詢集合耗效能而己
  763. db.SaveChanges();
  764. #endregion
  765. }
  766. }
  767. }
  768. }
  769. db.ChangeTracker.DetectChanges();
  770. }
  771. await Task.Delay(1000);
  772. // Thread.CurrentThread.Join(1000);
  773. }
  774. catch (Exception ex)
  775. {
  776. logger.Error(string.Format("ServerMessageTrigger Ex:{0}", ex.ToString()));
  777. }
  778. }
  779. }
  780. async private void HealthAlarmTrigger()
  781. {
  782. }
  783. private void AddConfirmMessage(string chargePointSerialNumber, int table_id, string requestId, string action, string msg_id)
  784. {
  785. NeedConfirmMessage _needConfirmMsg = new NeedConfirmMessage();
  786. _needConfirmMsg.Id = table_id;
  787. _needConfirmMsg.SentAction = action;
  788. _needConfirmMsg.SentOn = DateTime.Now;
  789. _needConfirmMsg.SentTimes = 1;
  790. _needConfirmMsg.ChargePointSerialNumber = chargePointSerialNumber;
  791. _needConfirmMsg.RequestId = requestId;
  792. _needConfirmMsg.SentUniqueId = msg_id;
  793. if (needConfirmActions.Contains(action))
  794. {
  795. lock (_lockConfirmPacketList)
  796. {
  797. needConfirmPacketList.Add(_needConfirmMsg);
  798. if (action == "GetConfiguration")
  799. {
  800. Console.WriteLine("AddConfirmMessage: " + msg_id);
  801. }
  802. }
  803. }
  804. }
  805. private void RemoveConfirmMessage()
  806. {
  807. var before_3mins = DateTime.Now.AddMinutes(-3);
  808. lock (_lockConfirmPacketList)
  809. {
  810. var removeList = needConfirmPacketList.Where(x => x.SentTimes == 0 || x.SentOn < before_3mins).ToList();
  811. foreach (var item in removeList)
  812. {
  813. needConfirmPacketList.Remove(item);
  814. }
  815. }
  816. }
  817. private bool ReConfirmMessage(MessageResult analysisResult)
  818. {
  819. bool confirmed = false;
  820. if (needConfirmActions.Contains(analysisResult.Action))
  821. {
  822. if (analysisResult.Action == "GetConfiguration")
  823. {
  824. Console.WriteLine("ReConfirmMessage: " + analysisResult.UUID);
  825. }
  826. NeedConfirmMessage foundRequest = null;
  827. lock (_lockConfirmPacketList)
  828. {
  829. foundRequest = needConfirmPacketList.Where(x => x.SentUniqueId == analysisResult.UUID).FirstOrDefault();
  830. }
  831. if (foundRequest != null && foundRequest.Id > 0)
  832. {
  833. foundRequest.SentTimes = 0;
  834. foundRequest.SentInterval = 0;
  835. analysisResult.RequestId = foundRequest.RequestId;
  836. using (var db = new MainDBContext())
  837. {
  838. var sc = db.ServerMessage.Where(x => x.Id == foundRequest.Id).FirstOrDefault();
  839. sc.InMessage = JsonConvert.SerializeObject(analysisResult.Message, Formatting.None);
  840. sc.ReceivedOn = DateTime.Now;
  841. db.SaveChanges();
  842. Console.WriteLine(string.Format("Now:{0} ServerMessage Id:{1} ", DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"), foundRequest.Id));
  843. }
  844. confirmed = true;
  845. }
  846. else if (analysisResult.Action == Actions.TriggerMessage.ToString())
  847. {
  848. confirmed = true;
  849. }
  850. else
  851. {
  852. logger.Error(string.Format("Received no record Action:{0} MessageId:{1} ", analysisResult.Action, analysisResult.UUID));
  853. }
  854. }
  855. return confirmed;
  856. }
  857. private void RemoveClient(ClientData session)
  858. {
  859. Console.WriteLine("*********");
  860. if (session != null)
  861. {
  862. logger.Trace("RemoveClient[" + session.ChargeBoxId + "]");
  863. RemoveClientDic(session);
  864. try
  865. {
  866. session.m_ReceiveData -= new ClientData.OCPPClientDataEventHandler<ClientData, String>(ReceivedMessage);
  867. // session.Close(CloseReason.ServerShutdown);
  868. }
  869. catch (Exception ex)
  870. {
  871. //logger.Warn("Close client socket error!!");
  872. logger.Warn(string.Format("Close client socket error!! {0} Msg:{1}", session.ChargeBoxId, ex.Message));
  873. }
  874. if (session != null)
  875. {
  876. session = null;
  877. }
  878. }
  879. }
  880. private void RemoveClientDic(ClientData session)
  881. {
  882. if (!string.IsNullOrEmpty(session.ChargeBoxId))
  883. {
  884. lock (_lockClientDic)
  885. {
  886. if (clientDic.ContainsKey(session.ChargeBoxId))
  887. {
  888. if(clientDic[session.ChargeBoxId].SessionID == session.SessionID)
  889. {
  890. logger.Debug(String.Format("ChargeBoxId:{0} Remove SessionId:{1} Removed SessionId:{2}", session.ChargeBoxId, session.SessionID, clientDic[session.ChargeBoxId].SessionID));
  891. clientDic.Remove(session.ChargeBoxId);
  892. logger.Trace("RemoveClient ContainsKey " + session.ChargeBoxId);
  893. }
  894. }
  895. }
  896. }
  897. }
  898. private void WarmUpLog()
  899. {
  900. using (var log = new ConnectionLogDBContext())
  901. {
  902. log.MachineConnectionLog.ToList();
  903. }
  904. }
  905. private void WriteMachineLog(ClientData clientData, string data, string messageType, string errorMsg = "", bool isSent = false)
  906. {
  907. try
  908. {
  909. if (clientData == null || string.IsNullOrEmpty(data)) return;
  910. using (var db = new ConnectionLogDBContext())
  911. {
  912. string sp = "[dbo].[uspInsertMachineConnectionLog] @CreatedOn," +
  913. "@ChargeBoxId,@MessageType,@Data,@Msg,@IsSent,@EVSEEndPoint,@Session";
  914. var dd = DateTime.Now;
  915. SqlParameter[] parameter =
  916. {
  917. new SqlParameter("CreatedOn",dd),
  918. new SqlParameter("ChargeBoxId",clientData.ChargeBoxId.Replace("'","''")),
  919. new SqlParameter("MessageType",messageType.Replace("'","''")),
  920. new SqlParameter("Data",data.Replace("'","''")),
  921. new SqlParameter("Msg",errorMsg.Replace("'","''")),
  922. new SqlParameter("IsSent",isSent),
  923. new SqlParameter("EVSEEndPoint",clientData.RemoteEndPoint==null?"123":clientData.RemoteEndPoint.ToString()),
  924. new SqlParameter("Session",clientData.SessionID)
  925. };
  926. db.Database.ExecuteSqlCommand(sp, parameter);
  927. }
  928. }
  929. catch (Exception ex)
  930. {
  931. Console.WriteLine(ex.ToString());
  932. }
  933. }
  934. }
  935. }