CoreProfileHandler.cs 64 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140
  1. using EVCB_OCPP.Domain;
  2. using EVCB_OCPP.Domain.Models.Database;
  3. using EVCB_OCPP.Packet.Features;
  4. using EVCB_OCPP.Packet.Messages;
  5. using EVCB_OCPP.Packet.Messages.Core;
  6. using EVCB_OCPP.Packet.Messages.SubTypes;
  7. using EVCB_OCPP.WSServer.Dto;
  8. using EVCB_OCPP.WSServer.Service;
  9. using Newtonsoft.Json;
  10. using NLog;
  11. using OCPPPackage.Profiles;
  12. using OCPPServer.Protocol;
  13. using System;
  14. using System.Collections.Generic;
  15. using System.Data.Entity;
  16. using System.Data.SqlClient;
  17. using System.Diagnostics;
  18. using System.Linq;
  19. using System.Threading.Tasks;
  20. namespace EVCB_OCPP.WSServer.Message
  21. {
  22. internal partial class ProfileHandler
  23. {
  24. static private ILogger logger = NLog.LogManager.GetCurrentClassLogger();
  25. async internal Task<MessageResult> ExecuteCoreRequest(Actions action, ClientData session, IRequest request)
  26. {
  27. Stopwatch watch = new Stopwatch();
  28. if (action == Actions.Heartbeat)
  29. {
  30. watch.Start();
  31. }
  32. MessageResult result = new MessageResult() { Success = false };
  33. try
  34. {
  35. switch (action)
  36. {
  37. case Actions.DataTransfer:
  38. {
  39. var confirm = new DataTransferConfirmation() { status = DataTransferStatus.Accepted };
  40. result.Message = confirm;
  41. result.Success = true;
  42. }
  43. break;
  44. case Actions.BootNotification:
  45. {
  46. BootNotificationRequest _request = request as BootNotificationRequest;
  47. int heartbeat_interval = GlobalConfig.GetHEARTBEAT_INTERVAL();
  48. using (var db = new MainDBContext())
  49. {
  50. var _machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault();
  51. _machine.ChargeBoxSerialNumber = string.IsNullOrEmpty(_request.chargeBoxSerialNumber) ? string.Empty : _request.chargeBoxSerialNumber;
  52. _machine.ChargePointSerialNumber = string.IsNullOrEmpty(_request.chargePointSerialNumber) ? string.Empty : _request.chargePointSerialNumber;
  53. _machine.ChargePointModel = string.IsNullOrEmpty(_request.chargePointModel) ? string.Empty : _request.chargePointModel;
  54. _machine.ChargePointVendor = string.IsNullOrEmpty(_request.chargePointVendor) ? string.Empty : _request.chargePointVendor;
  55. _machine.FW_CurrentVersion = string.IsNullOrEmpty(_request.firmwareVersion) ? string.Empty : _request.firmwareVersion;
  56. //_machine.Iccid = string.IsNullOrEmpty(_request.iccid) ? string.Empty : _request.iccid;
  57. _machine.Iccid = DateTime.UtcNow.ToString("yy-MM-dd HH:mm");
  58. _machine.Imsi = string.IsNullOrEmpty(_request.imsi) ? string.Empty : _request.imsi;
  59. _machine.MeterSerialNumber = string.IsNullOrEmpty(_request.meterSerialNumber) ? string.Empty : _request.meterSerialNumber;
  60. _machine.MeterType = string.IsNullOrEmpty(_request.meterType) ? string.Empty : _request.meterType;
  61. db.SaveChanges();
  62. var configVaule = db.MachineConfiguration.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.ConfigureName == StandardConfiguration.HeartbeatInterval)
  63. .Select(x => x.ConfigureSetting).FirstOrDefault();
  64. if (configVaule != null)
  65. {
  66. int.TryParse(configVaule, out heartbeat_interval);
  67. }
  68. }
  69. var confirm = new BootNotificationConfirmation() { currentTime = DateTime.UtcNow, interval = session.IsPending ? heartbeat_interval : 5, status = session.IsPending ? Packet.Messages.SubTypes.RegistrationStatus.Accepted : RegistrationStatus.Pending };
  70. session.IsPending = !session.IsPending;
  71. result.Message = confirm;
  72. result.Success = true;
  73. }
  74. break;
  75. case Actions.StatusNotification:
  76. {
  77. //只保留最新上報狀況
  78. StatusNotificationRequest _request = request as StatusNotificationRequest;
  79. int preStatus = 0;
  80. using (var db = new MainDBContext())
  81. {
  82. var _oldStatus = db.ConnectorStatus.Where(x => x.ChargeBoxId == session.ChargeBoxId
  83. && x.ConnectorId == _request.connectorId).AsNoTracking().FirstOrDefault();
  84. if (_oldStatus != null && (_request.status != (ChargePointStatus)_oldStatus.Status || _request.status == ChargePointStatus.Faulted))
  85. {
  86. preStatus = _oldStatus.Status;
  87. db.Configuration.AutoDetectChangesEnabled = false;
  88. db.Configuration.ValidateOnSaveEnabled = false;
  89. db.ConnectorStatus.Attach(_oldStatus);
  90. _oldStatus.CreatedOn = _request.timestamp.HasValue ? _request.timestamp.Value : DateTime.UtcNow;
  91. _oldStatus.Status = (int)_request.status;
  92. _oldStatus.ChargePointErrorCodeId = (int)_request.errorCode;
  93. _oldStatus.ErrorInfo = string.IsNullOrEmpty(_request.info) ? string.Empty : _request.info;
  94. _oldStatus.VendorId = string.IsNullOrEmpty(_request.vendorId) ? string.Empty : _request.vendorId;
  95. _oldStatus.VendorErrorCode = string.IsNullOrEmpty(_request.vendorErrorCode) ? string.Empty : _request.vendorErrorCode;
  96. db.Entry(_oldStatus).Property(x => x.CreatedOn).IsModified = true;
  97. db.Entry(_oldStatus).Property(x => x.Status).IsModified = true;
  98. db.Entry(_oldStatus).Property(x => x.ChargePointErrorCodeId).IsModified = true;
  99. db.Entry(_oldStatus).Property(x => x.ErrorInfo).IsModified = true;
  100. db.Entry(_oldStatus).Property(x => x.VendorId).IsModified = true;
  101. db.Entry(_oldStatus).Property(x => x.VendorErrorCode).IsModified = true;
  102. }
  103. if (_oldStatus == null)
  104. {
  105. var _currentStatus = new Domain.Models.Database.ConnectorStatus()
  106. {
  107. ChargeBoxId = session.ChargeBoxId,
  108. ConnectorId = (byte)_request.connectorId,
  109. CreatedOn = _request.timestamp.HasValue ? _request.timestamp.Value : DateTime.UtcNow,
  110. Status = (int)_request.status,
  111. ChargePointErrorCodeId = (int)_request.errorCode,
  112. ErrorInfo = string.IsNullOrEmpty(_request.info) ? string.Empty : _request.info,
  113. VendorId = string.IsNullOrEmpty(_request.vendorId) ? string.Empty : _request.vendorId,
  114. VendorErrorCode = string.IsNullOrEmpty(_request.vendorErrorCode) ? string.Empty : _request.vendorErrorCode,
  115. Id = Guid.NewGuid().ToString()
  116. };
  117. db.ConnectorStatus.Add(_currentStatus);
  118. }
  119. if (_request.status == Packet.Messages.SubTypes.ChargePointStatus.Faulted)
  120. {
  121. db.MachineError.Add(new MachineError()
  122. {
  123. ConnectorId = (byte)_request.connectorId,
  124. CreatedOn = _request.timestamp.HasValue ? _request.timestamp.Value : DateTime.UtcNow,
  125. Status = (int)_request.status,
  126. ChargeBoxId = session.ChargeBoxId,
  127. ErrorCodeId = (int)_request.errorCode,
  128. ErrorInfo = string.IsNullOrEmpty(_request.info) ? string.Empty : _request.info,
  129. PreStatus = _oldStatus == null ? -1 : preStatus,
  130. VendorErrorCode = string.IsNullOrEmpty(_request.vendorErrorCode) ? string.Empty : _request.vendorErrorCode,
  131. VendorId = string.IsNullOrEmpty(_request.vendorId) ? string.Empty : _request.vendorId
  132. });
  133. }
  134. db.SaveChanges();
  135. }
  136. if (_request.status == Packet.Messages.SubTypes.ChargePointStatus.Faulted)
  137. {
  138. var businessService = BusinessServiceFactory.CreateBusinessService(session.CustomerId.ToString());
  139. var notification = businessService.NotifyFaultStatus(new ErrorDetails()
  140. {
  141. ChargeBoxId = session.ChargeBoxId,
  142. ConnectorId = _request.connectorId,
  143. ErrorCode = _request.errorCode,
  144. Info = string.IsNullOrEmpty(_request.info) ? string.Empty : _request.info,
  145. OCcuredOn = _request.timestamp ?? DateTime.UtcNow,
  146. VendorErrorCode = string.IsNullOrEmpty(_request.vendorErrorCode) ? string.Empty : _request.vendorErrorCode,
  147. });
  148. }
  149. var confirm = new StatusNotificationConfirmation() { };
  150. result.Message = confirm;
  151. result.Success = true;
  152. }
  153. break;
  154. case Actions.Heartbeat:
  155. {
  156. var confirm = new HeartbeatConfirmation() { currentTime = DateTime.UtcNow };
  157. result.Message = confirm;
  158. result.Success = true;
  159. }
  160. break;
  161. case Actions.MeterValues:
  162. {
  163. MeterValuesRequest _request = request as MeterValuesRequest;
  164. decimal energy_kwh = 0;
  165. if (_request.meterValue.Count > 0)
  166. {
  167. using (var db = new MeterValueDBContext())
  168. {
  169. foreach (var item in _request.meterValue)
  170. {
  171. foreach (var sampleVaule in item.sampledValue)
  172. {
  173. decimal value = Convert.ToDecimal(sampleVaule.value);
  174. if (sampleVaule.context == ReadingContext.Sample_Periodic && sampleVaule.measurand == Measurand.Energy_Active_Import_Interval)
  175. {
  176. energy_kwh = sampleVaule.unit == UnitOfMeasure.Wh ? Decimal.Divide(value, 1000) : value;
  177. }
  178. string sp = "[dbo].[uspInsertMeterValueRecord] @ChargeBoxId," +
  179. "@ConnectorId,@Value,@CreatedOn,@ContextId,@FormatId,@MeasurandId,@PhaseId,@LocationId,@UnitId,@TransactionId";
  180. List<SqlParameter> parameter = new List<SqlParameter>
  181. {
  182. new SqlParameter("ChargeBoxId",session.ChargeBoxId),
  183. new SqlParameter("ConnectorId", (byte)_request.connectorId),
  184. new SqlParameter("Value",value),
  185. new SqlParameter("CreatedOn",item.timestamp),
  186. new SqlParameter("ContextId",sampleVaule.context.HasValue ? (int)sampleVaule.context : 0),
  187. new SqlParameter("FormatId",sampleVaule.format.HasValue ? (int)sampleVaule.format : 0),
  188. new SqlParameter("MeasurandId",sampleVaule.measurand.HasValue ? (int)sampleVaule.measurand : 0),
  189. new SqlParameter("PhaseId",sampleVaule.phase.HasValue ? (int)sampleVaule.phase : 0),
  190. new SqlParameter("LocationId",sampleVaule.location.HasValue ? (int)sampleVaule.location : 0),
  191. new SqlParameter("UnitId",sampleVaule.unit.HasValue ? (int)sampleVaule.unit : 0),
  192. new SqlParameter("TransactionId",_request.transactionId.HasValue?_request.transactionId:-1),
  193. };
  194. db.Database.ExecuteSqlCommand(sp, parameter.ToArray());
  195. }
  196. }
  197. }
  198. }
  199. // if (energy_kwh > 0)
  200. {
  201. try
  202. {
  203. if (session.IsBilling)
  204. if (session.IsBilling)
  205. {
  206. using (var db = new MainDBContext())
  207. {
  208. db.ServerMessage.Add(new ServerMessage()
  209. {
  210. ChargeBoxId = session.ChargeBoxId,
  211. CreatedBy = "Server",
  212. CreatedOn = DateTime.UtcNow,
  213. OutAction = Actions.DataTransfer.ToString(),
  214. OutRequest = JsonConvert.SerializeObject(
  215. new DataTransferRequest()
  216. {
  217. messageId = "ID_TxEnergy",
  218. vendorId = "Phihong Technology",
  219. data = JsonConvert.SerializeObject(new { txId = _request.transactionId, ConnectorId = _request.connectorId })
  220. },
  221. new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
  222. SerialNo = Guid.NewGuid().ToString(),
  223. InMessage = string.Empty
  224. });
  225. db.SaveChanges();
  226. }
  227. }
  228. }
  229. catch (Exception ex)
  230. {
  231. Console.WriteLine(string.Format("{0} :{1}", session.ChargeBoxId + " RunningCost", ex.Message));
  232. }
  233. }
  234. var confirm = new MeterValuesConfirmation() { };
  235. result.Message = confirm;
  236. result.Success = true;
  237. }
  238. break;
  239. case Actions.StartTransaction:
  240. {
  241. StartTransactionRequest _request = request as StartTransactionRequest;
  242. int _transactionId = -1;
  243. var businessService = BusinessServiceFactory.CreateBusinessService(session.CustomerId.ToString());
  244. var _idTagInfo = _request.idTag == "Backend" ? new IdTagInfo() { expiryDate = DateTime.UtcNow.AddDays(1), status = AuthorizationStatus.Accepted } : await businessService.Authorize(session.ChargeBoxId, _request.idTag);
  245. //特例****飛宏客戶旗下的電樁,若遇到Portal沒回應的狀況 ~允許充電
  246. if (session.CustomerId.ToString().ToUpper() == "8456AED9-6DD9-4BF3-A94C-9F5DCB9506F7" && _idTagInfo.status == AuthorizationStatus.ConcurrentTx)
  247. {
  248. _idTagInfo = new IdTagInfo() { expiryDate = DateTime.UtcNow.AddDays(1), status = AuthorizationStatus.Accepted };
  249. }
  250. using (var db = new MainDBContext())
  251. {
  252. var _CustomerId = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).Include(x => x.Customer).
  253. Select(x => x.CustomerId).FirstOrDefault();
  254. var _existedTx = db.TransactionRecord.Where(x => x.CustomerId == _CustomerId && x.ChargeBoxId == session.ChargeBoxId
  255. && x.ConnectorId == _request.connectorId && x.StartTime == _request.timestamp).Select(C => new { C.Id }).AsNoTracking().FirstOrDefault();
  256. TransactionRecord _newTransaction = new TransactionRecord();
  257. if (_existedTx == null)
  258. {
  259. _newTransaction = new TransactionRecord()
  260. {
  261. ChargeBoxId = session.ChargeBoxId,
  262. ConnectorId = (byte)_request.connectorId,
  263. CreatedOn = DateTime.UtcNow,
  264. StartIdTag = _request.idTag,
  265. MeterStart = _request.meterStart,
  266. CustomerId = _CustomerId,
  267. StartTime = _request.timestamp.ToUniversalTime(),
  268. ReservationId = _request.reservationId.HasValue ? _request.reservationId.Value : 0,
  269. Fee = !session.IsBilling ? string.Empty : session.BillingMethod == 1 ? JsonConvert.SerializeObject(session.ChargingPrices) + "|" + session.Currency : session.HRPrice + "|" + session.Currency
  270. };
  271. db.TransactionRecord.Add(_newTransaction);
  272. db.SaveChanges();
  273. _transactionId = _newTransaction.Id;
  274. logger.Info("***************************************************** ");
  275. logger.Info(string.Format("{0} :TransactionId {1} ", session.ChargeBoxId, _newTransaction.Id));
  276. logger.Info("***************************************************** ");
  277. }
  278. else
  279. {
  280. _transactionId = _existedTx.Id;
  281. logger.Error("Duplication ***************************************************** " + _existedTx.Id);
  282. }
  283. }
  284. var confirm = new StartTransactionConfirmation()
  285. {
  286. idTagInfo = _idTagInfo,
  287. transactionId = _transactionId
  288. };
  289. result.Message = confirm;
  290. result.Success = true;
  291. }
  292. break;
  293. case Actions.StopTransaction:
  294. {
  295. StopTransactionRequest _request = request as StopTransactionRequest;
  296. int _ConnectorId = 0;
  297. var businessService = BusinessServiceFactory.CreateBusinessService(session.CustomerId.ToString());
  298. //特例****飛宏客戶旗下的電樁,若遇到Portal沒回應的狀況 ~允許充電
  299. var _idTagInfo = string.IsNullOrEmpty(_request.idTag) ? null : (_request.idTag == "Backend" ? new IdTagInfo() { expiryDate = DateTime.UtcNow.AddDays(1), status = AuthorizationStatus.Accepted } : await businessService.Authorize(session.ChargeBoxId, _request.idTag));
  300. if (session.CustomerId.ToString().ToUpper() == "8456AED9-6DD9-4BF3-A94C-9F5DCB9506F7" && _idTagInfo != null && _idTagInfo.status == AuthorizationStatus.ConcurrentTx)
  301. {
  302. _idTagInfo = new IdTagInfo() { expiryDate = DateTime.UtcNow.AddDays(1), status = AuthorizationStatus.Accepted };
  303. }
  304. using (var db = new MainDBContext())
  305. {
  306. var transaction = db.TransactionRecord.Where(x => x.Id == _request.transactionId
  307. && x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault();
  308. if (transaction != null)
  309. {
  310. _ConnectorId = transaction.ConnectorId;
  311. transaction.MeterStop = _request.meterStop;
  312. transaction.StopTime = _request.timestamp.ToUniversalTime();
  313. transaction.StopReasonId = _request.reason.HasValue ? (int)_request.reason.Value : 0;
  314. transaction.StopIdTag = _request.idTag;
  315. transaction.Receipt = string.Empty;
  316. transaction.Cost = session.IsBilling ? -1 : 0;
  317. await db.SaveChangesAsync();
  318. var confirm = new StopTransactionConfirmation()
  319. {
  320. idTagInfo = _idTagInfo
  321. };
  322. if (session.IsBilling)
  323. {
  324. db.ServerMessage.Add(new ServerMessage()
  325. {
  326. ChargeBoxId = session.ChargeBoxId,
  327. CreatedBy = "Server",
  328. CreatedOn = DateTime.UtcNow,
  329. OutAction = Actions.DataTransfer.ToString(),
  330. OutRequest = JsonConvert.SerializeObject(
  331. new DataTransferRequest()
  332. {
  333. messageId = "ID_TxEnergy",
  334. vendorId = "Phihong Technology",
  335. data = JsonConvert.SerializeObject(new { txId = _request.transactionId, ConnectorId = transaction.ConnectorId })
  336. },
  337. new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
  338. SerialNo = Guid.NewGuid().ToString(),
  339. InMessage = string.Empty
  340. });
  341. db.SaveChanges();
  342. }
  343. result.Message = confirm;
  344. result.Success = true;
  345. }
  346. else
  347. {
  348. result.Exception = new Exception("Can't find transactionId " + _request.transactionId);
  349. }
  350. }
  351. if (_request.transactionData != null)
  352. {
  353. if (_request.transactionData.Count > 0)
  354. {
  355. using (var _meterDb = new MeterValueDBContext())
  356. {
  357. foreach (var item in _request.transactionData)
  358. {
  359. foreach (var sampleVaule in item.sampledValue)
  360. {
  361. decimal value = Convert.ToDecimal(sampleVaule.value);
  362. string sp = "[dbo].[uspInsertMeterValueRecord] @ChargeBoxId," +
  363. "@ConnectorId,@Value,@CreatedOn,@ContextId,@FormatId,@MeasurandId,@PhaseId,@LocationId,@UnitId,@TransactionId";
  364. List<SqlParameter> parameter = new List<SqlParameter>
  365. {
  366. new SqlParameter("ChargeBoxId",session.ChargeBoxId),
  367. new SqlParameter("ConnectorId", (byte)_ConnectorId),
  368. new SqlParameter("Value",value),
  369. new SqlParameter("CreatedOn",item.timestamp),
  370. new SqlParameter("ContextId",sampleVaule.context.HasValue ? (int)sampleVaule.context : 0),
  371. new SqlParameter("FormatId",sampleVaule.format.HasValue ? (int)sampleVaule.format : 0),
  372. new SqlParameter("MeasurandId",sampleVaule.measurand.HasValue ? (int)sampleVaule.measurand : 0),
  373. new SqlParameter("PhaseId",sampleVaule.phase.HasValue ? (int)sampleVaule.phase : 0),
  374. new SqlParameter("LocationId",sampleVaule.location.HasValue ? (int)sampleVaule.location : 0),
  375. new SqlParameter("UnitId",sampleVaule.unit.HasValue ? (int)sampleVaule.unit : 0),
  376. new SqlParameter("TransactionId",_request.transactionId),
  377. };
  378. _meterDb.Database.ExecuteSqlCommand(sp, parameter.ToArray());
  379. }
  380. }
  381. }
  382. }
  383. }
  384. }
  385. break;
  386. case Actions.Authorize:
  387. {
  388. AuthorizeRequest _request = request as AuthorizeRequest;
  389. //特例****飛宏客戶旗下的電樁,若遇到Portal沒回應的狀況 ~允許充電
  390. var businessService = BusinessServiceFactory.CreateBusinessService(session.CustomerId.ToString());
  391. var confirm = new AuthorizeConfirmation()
  392. {
  393. idTagInfo = _request.idTag == "Backend" ? new IdTagInfo() { expiryDate = DateTime.UtcNow.AddDays(1), status = AuthorizationStatus.Accepted } : await businessService.Authorize(session.ChargeBoxId, _request.idTag)
  394. };
  395. if (session.CustomerId.ToString().ToUpper() == "8456AED9-6DD9-4BF3-A94C-9F5DCB9506F7" && confirm.idTagInfo.status == AuthorizationStatus.ConcurrentTx)
  396. {
  397. confirm.idTagInfo = new IdTagInfo() { expiryDate = DateTime.UtcNow.AddDays(1), status = AuthorizationStatus.Accepted };
  398. }
  399. result.Message = confirm;
  400. result.Success = true;
  401. }
  402. break;
  403. default:
  404. {
  405. Console.WriteLine(string.Format("Not Implement {0} Logic(ExecuteCoreRequest)", request.GetType().ToString().Replace("OCPPPackage.Messages.Core.", "")));
  406. }
  407. break;
  408. }
  409. }
  410. catch (Exception ex)
  411. {
  412. logger.Fatal(string.Format("chargeBoxId:{0} {1}", session.ChargeBoxId, action));
  413. logger.Fatal(string.Format("Data {0}", request.ToString()));
  414. logger.Fatal(string.Format("Error {0}", ex.ToString()));
  415. result.Exception = ex;
  416. }
  417. if (action == Actions.Heartbeat)
  418. {
  419. watch.Stop();
  420. if (watch.ElapsedMilliseconds / 1000 > 3)
  421. {
  422. logger.Error("Processing Hearbeat costs " + watch.ElapsedMilliseconds / 1000 + " seconds");
  423. }
  424. }
  425. return result;
  426. }
  427. internal MessageResult ExecuteCoreConfirm(Actions action, ClientData session, IConfirmation confirm, string requestId)
  428. {
  429. MessageResult result = new MessageResult() { Success = true };
  430. try
  431. {
  432. switch (action)
  433. {
  434. case Actions.DataTransfer:
  435. {
  436. DataTransferConfirmation _confirm = confirm as DataTransferConfirmation;
  437. DataTransferRequest _request = _confirm.GetRequest() as DataTransferRequest;
  438. using (var db = new MainDBContext())
  439. {
  440. var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
  441. x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
  442. if (operation != null)
  443. {
  444. operation.FinishedOn = DateTime.UtcNow;
  445. operation.Status = 1;//電樁有回覆
  446. operation.EVSE_Status = (int)_confirm.status;
  447. operation.EVSE_Value = string.IsNullOrEmpty(_confirm.data) ? "" : _confirm.data;
  448. db.SaveChanges();
  449. }
  450. if (_request.messageId == "ID_FirmwareVersion")
  451. {
  452. var machine = new Machine() { Id = session.MachineId };
  453. if (machine != null)
  454. {
  455. db.Configuration.AutoDetectChangesEnabled = false;
  456. db.Configuration.ValidateOnSaveEnabled = false;
  457. db.Machine.Attach(machine);
  458. machine.BoardVersions = _confirm.data;
  459. db.Entry(machine).Property(x => x.BoardVersions).IsModified = true;
  460. db.SaveChanges();
  461. }
  462. }
  463. if (_request.messageId == "ID_TxEnergy")
  464. {
  465. if (_confirm.status == DataTransferStatus.Accepted)
  466. {
  467. string receipt = string.Empty;
  468. List<ChargingBill> bill = new List<ChargingBill>();
  469. List<ChargingPrice> chargingPrices = new List<ChargingPrice>();
  470. var txEnergy = JsonConvert.DeserializeObject<TransactionEnergy>(_confirm.data);
  471. var feedto = db.TransactionRecord.Where(x => x.Id == txEnergy.TxId).Select(x => new { Fee = x.Fee, StopTime = x.StopTime, StartTime = x.StartTime }).FirstOrDefault();
  472. if (feedto == null || string.IsNullOrEmpty(feedto.Fee)) return result;
  473. string currency = feedto.Fee.Substring(feedto.Fee.Length - 3);
  474. decimal sum = 0;
  475. if (feedto.Fee.Length > 10)
  476. {
  477. chargingPrices = JsonConvert.DeserializeObject<List<ChargingPrice>>(feedto.Fee.Split('|')[0]);
  478. foreach (var item in txEnergy.PeriodEnergy)
  479. {
  480. var periodEnergy = Math.Round(item.Value, 2, MidpointRounding.AwayFromZero);
  481. string startTime = item.Key.Length == 1 ? "0" + item.Key + ":00" : item.Key + ":00";
  482. decimal perfee = 0;
  483. if (chargingPrices.Count == 1)
  484. {
  485. perfee = Decimal.Multiply(periodEnergy, chargingPrices[0].Fee);
  486. if (bill.Count == 0)
  487. {
  488. bill.Add(new ChargingBill()
  489. {
  490. StartTime = "00:00",
  491. EndTime = "23:59",
  492. Fee = chargingPrices[0].Fee
  493. });
  494. }
  495. bill[0].PeriodEnergy += periodEnergy;
  496. }
  497. else
  498. {
  499. var price = chargingPrices.Where(x => x.StartTime == startTime).FirstOrDefault();
  500. perfee = Decimal.Multiply(periodEnergy, price.Fee);
  501. bill.Add(new ChargingBill()
  502. {
  503. StartTime = price.StartTime,
  504. EndTime = price.EndTime,
  505. PeriodEnergy = periodEnergy,
  506. Fee = chargingPrices[0].Fee
  507. });
  508. }
  509. if (bill.Count > 0)
  510. {
  511. bill[bill.Count - 1].Total += DollarRounding(perfee, session.Currency);
  512. sum += bill[bill.Count - 1].Total;
  513. if (bill.Count == 1)
  514. {
  515. sum = bill[bill.Count - 1].Total;
  516. }
  517. }
  518. }
  519. }
  520. else
  521. {
  522. // 以時計費
  523. var fee = decimal.Parse(feedto.Fee.Split('|')[0]);
  524. var totalHours = Math.Round(DateTime.UtcNow.Subtract(feedto.StartTime).TotalHours, 2, MidpointRounding.AwayFromZero);
  525. sum = Decimal.Multiply((decimal)totalHours, fee);
  526. sum = DollarRounding(sum, session.Currency);
  527. receipt = totalHours + "hrs @ $" + fee + "/hr =" + sum;
  528. }
  529. if (feedto.StopTime != GlobalConfig.DefaultNullTime)
  530. {
  531. var tx = db.TransactionRecord.Where(x => x.Id == txEnergy.TxId).FirstOrDefault();
  532. if (tx == null)
  533. {
  534. Console.WriteLine("Tx is empty");
  535. return result;
  536. }
  537. var startTime = new DateTime(tx.StartTime.Year, tx.StartTime.Month, tx.StartTime.Day, tx.StartTime.Hour, 0, 0);
  538. List<ChargingBill> confirmbill = new List<ChargingBill>();
  539. while (startTime < tx.StopTime)
  540. {
  541. if (bill.Count == 1)
  542. {
  543. confirmbill = bill;
  544. receipt = string.Format("{0} kWh @ ${1}/kWh={2}", bill[0].PeriodEnergy, bill[0].Fee, bill[0].Total);
  545. break;
  546. }
  547. if (bill.Count > 1)
  548. {
  549. confirmbill.Add(bill.Where(x => x.StartTime == startTime.ToString("HH:00")).FirstOrDefault());
  550. if (confirmbill.Count == 24) break;
  551. if (confirmbill.Count > 1)
  552. {
  553. receipt += "|";
  554. }
  555. receipt += string.Format("{0}~{1} {2} kWh @ ${3}/kWh={4}", confirmbill[confirmbill.Count - 1].StartTime, confirmbill[confirmbill.Count - 1].EndTime,
  556. confirmbill[confirmbill.Count - 1].PeriodEnergy, bill[0].Fee, confirmbill[confirmbill.Count - 1].Total);
  557. }
  558. startTime = startTime.AddHours(1);
  559. }
  560. if (bill.Count > 0)
  561. {
  562. confirmbill = confirmbill.Where(x => string.IsNullOrEmpty(x.StartTime) == false).ToList();
  563. }
  564. tx.Cost = sum;
  565. tx.Receipt = receipt;
  566. db.Configuration.AutoDetectChangesEnabled = false;
  567. db.Configuration.ValidateOnSaveEnabled = false;
  568. db.TransactionRecord.Attach(tx);
  569. db.Entry(tx).Property(x => x.Cost).IsModified = true;
  570. db.Entry(tx).Property(x => x.Receipt).IsModified = true;
  571. db.ServerMessage.Add(new ServerMessage()
  572. {
  573. ChargeBoxId = session.ChargeBoxId,
  574. CreatedBy = "Server",
  575. CreatedOn = DateTime.UtcNow,
  576. OutAction = Actions.DataTransfer.ToString(),
  577. OutRequest = JsonConvert.SerializeObject(
  578. new DataTransferRequest()
  579. {
  580. messageId = "FinalCost",
  581. vendorId = "Phihong Technology",
  582. data = JsonConvert.SerializeObject(new
  583. {
  584. txId = txEnergy.TxId,
  585. description = string.Format("Connection Fee: $0.00 {0}; Session Fee: ${1} {0}; Occupancy Fee: " +
  586. "$0.00 {0}; Total Cost: ${1} {0}; Account Balance: $10.00 {0}", currency, sum)
  587. })
  588. },
  589. new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
  590. SerialNo = Guid.NewGuid().ToString(),
  591. InMessage = string.Empty
  592. }); ;
  593. db.SaveChanges();
  594. }
  595. else
  596. {
  597. db.ServerMessage.Add(new ServerMessage()
  598. {
  599. ChargeBoxId = session.ChargeBoxId,
  600. CreatedBy = "Server",
  601. CreatedOn = DateTime.UtcNow,
  602. OutAction = Actions.DataTransfer.ToString(),
  603. OutRequest = JsonConvert.SerializeObject(
  604. new DataTransferRequest()
  605. {
  606. messageId = "RunningCost",
  607. vendorId = "Phihong Technology",
  608. data = JsonConvert.SerializeObject(new
  609. {
  610. txId = txEnergy.TxId,
  611. description = string.Format("Connection Fee: $0.00 {0}; Session Fee: ${1} {0}; Occupancy Fee: " +
  612. "$0.00 {0}; Total Cost: ${1} {0}; Account Balance: $0.00 {0}", currency, sum)
  613. })
  614. },
  615. new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
  616. SerialNo = Guid.NewGuid().ToString(),
  617. InMessage = string.Empty
  618. }); ;
  619. db.SaveChanges();
  620. }
  621. }
  622. }
  623. }
  624. }
  625. break;
  626. case Actions.ChangeAvailability:
  627. {
  628. ChangeAvailabilityConfirmation _confirm = confirm as ChangeAvailabilityConfirmation;
  629. ChangeAvailabilityRequest _request = _confirm.GetRequest() as ChangeAvailabilityRequest;
  630. using (var db = new MainDBContext())
  631. {
  632. var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
  633. x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
  634. if (operation != null)
  635. {
  636. operation.FinishedOn = DateTime.UtcNow;
  637. operation.Status = 1;//電樁有回覆
  638. operation.EVSE_Status = (int)_confirm.status;
  639. operation.EVSE_Value = _confirm.status.ToString();
  640. db.SaveChanges();
  641. }
  642. }
  643. }
  644. break;
  645. case Actions.ClearCache:
  646. {
  647. ClearCacheConfirmation _confirm = confirm as ClearCacheConfirmation;
  648. ClearCacheRequest _request = _confirm.GetRequest() as ClearCacheRequest;
  649. using (var db = new MainDBContext())
  650. {
  651. var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
  652. x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
  653. if (operation != null)
  654. {
  655. operation.FinishedOn = DateTime.UtcNow;
  656. operation.Status = 1;//電樁有回覆
  657. operation.EVSE_Status = (int)_confirm.status;
  658. operation.EVSE_Value = _confirm.status.ToString();
  659. db.SaveChanges();
  660. }
  661. }
  662. }
  663. break;
  664. case Actions.RemoteStartTransaction:
  665. {
  666. RemoteStartTransactionConfirmation _confirm = confirm as RemoteStartTransactionConfirmation;
  667. RemoteStartTransactionRequest _request = _confirm.GetRequest() as RemoteStartTransactionRequest;
  668. using (var db = new MainDBContext())
  669. {
  670. var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
  671. x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
  672. if (operation != null)
  673. {
  674. operation.FinishedOn = DateTime.UtcNow;
  675. operation.Status = 1;//電樁有回覆
  676. operation.EVSE_Status = (int)_confirm.status;
  677. operation.EVSE_Value = _confirm.status.ToString();
  678. db.SaveChanges();
  679. }
  680. }
  681. }
  682. break;
  683. case Actions.RemoteStopTransaction:
  684. {
  685. RemoteStopTransactionConfirmation _confirm = confirm as RemoteStopTransactionConfirmation;
  686. RemoteStopTransactionRequest _request = _confirm.GetRequest() as RemoteStopTransactionRequest;
  687. using (var db = new MainDBContext())
  688. {
  689. var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
  690. x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
  691. if (operation != null)
  692. {
  693. operation.FinishedOn = DateTime.UtcNow;
  694. operation.Status = 1;//電樁有回覆
  695. operation.EVSE_Status = (int)_confirm.status;
  696. operation.EVSE_Value = _confirm.status.ToString();
  697. db.SaveChanges();
  698. }
  699. }
  700. }
  701. break;
  702. case Actions.Reset:
  703. {
  704. ResetConfirmation _confirm = confirm as ResetConfirmation;
  705. ResetRequest _request = _confirm.GetRequest() as ResetRequest;
  706. using (var db = new MainDBContext())
  707. {
  708. var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
  709. x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
  710. if (operation != null)
  711. {
  712. operation.FinishedOn = DateTime.UtcNow;
  713. operation.Status = 1;//電樁有回覆
  714. operation.EVSE_Status = (int)_confirm.status;
  715. operation.EVSE_Value = _confirm.status.ToString();
  716. db.SaveChanges();
  717. }
  718. }
  719. }
  720. break;
  721. case Actions.ChangeConfiguration:
  722. {
  723. ChangeConfigurationConfirmation _confirm = confirm as ChangeConfigurationConfirmation;
  724. ChangeConfigurationRequest _request = _confirm.GetRequest() as ChangeConfigurationRequest;
  725. using (var db = new MainDBContext())
  726. {
  727. var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
  728. x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
  729. if (operation != null)
  730. {
  731. operation.FinishedOn = DateTime.UtcNow;
  732. operation.Status = 1;//電樁有回覆
  733. operation.EVSE_Status = (int)_confirm.status;
  734. operation.EVSE_Value = _confirm.status.ToString();
  735. }
  736. if (_confirm.status == Packet.Messages.SubTypes.ConfigurationStatus.Accepted || _confirm.status == Packet.Messages.SubTypes.ConfigurationStatus.RebootRequired)
  737. {
  738. var configure = db.MachineConfiguration.Where(x => x.ChargeBoxId == session.ChargeBoxId).ToList();
  739. var foundConfig = configure.Find(x => x.ConfigureName == _request.key);
  740. if (foundConfig != null)
  741. {
  742. foundConfig.ReadOnly = false;
  743. foundConfig.ConfigureSetting = _request.value;
  744. }
  745. else
  746. {
  747. db.MachineConfiguration.Add(new MachineConfiguration()
  748. {
  749. ChargeBoxId = session.ChargeBoxId,
  750. ConfigureName = _request.key,
  751. ReadOnly = false,
  752. ConfigureSetting = _request.value
  753. });
  754. }
  755. }
  756. db.SaveChanges();
  757. }
  758. }
  759. break;
  760. case Actions.GetConfiguration:
  761. {
  762. try
  763. {
  764. GetConfigurationConfirmation _confirm = confirm as GetConfigurationConfirmation;
  765. // GetConfigurationRequest _request = _confirm.GetRequest() as GetConfigurationRequest;
  766. using (var db = new MainDBContext())
  767. {
  768. var configure = db.MachineConfiguration.Where(x => x.ChargeBoxId == session.ChargeBoxId).ToList();
  769. if (_confirm.configurationKey != null)
  770. {
  771. foreach (var item in _confirm.configurationKey)
  772. {
  773. string oldValue = string.Empty;
  774. if (item.key == null)
  775. {
  776. Console.WriteLine("*********************");
  777. }
  778. var foundConfig = configure.Find(x => x.ConfigureName == item.key);
  779. if (foundConfig != null)
  780. {
  781. if (foundConfig.ConfigureName == null)
  782. {
  783. Console.WriteLine("*********************");
  784. }
  785. if (foundConfig.ConfigureName == "SecurityProfile")
  786. {
  787. oldValue = foundConfig.ConfigureSetting;
  788. }
  789. foundConfig.ReadOnly = item.IsReadOnly;
  790. foundConfig.ConfigureSetting = string.IsNullOrEmpty(item.value) ? string.Empty : item.value;
  791. }
  792. else
  793. {
  794. db.MachineConfiguration.Add(new MachineConfiguration()
  795. {
  796. ChargeBoxId = session.ChargeBoxId,
  797. ConfigureName = item.key,
  798. ReadOnly = item.IsReadOnly,
  799. ConfigureSetting = string.IsNullOrEmpty(item.value) ? string.Empty : item.value,
  800. Exists = true
  801. });
  802. }
  803. }
  804. }
  805. if (_confirm.unknownKey != null)
  806. {
  807. foreach (var item in _confirm.unknownKey)
  808. {
  809. var foundConfig = configure.Find(x => x.ConfigureName == item);
  810. if (foundConfig != null)
  811. {
  812. foundConfig.ReadOnly = true;
  813. foundConfig.ConfigureSetting = string.Empty;
  814. foundConfig.Exists = false;
  815. }
  816. else
  817. {
  818. db.MachineConfiguration.Add(new MachineConfiguration()
  819. {
  820. ChargeBoxId = session.ChargeBoxId,
  821. ConfigureName = item
  822. });
  823. }
  824. }
  825. }
  826. var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
  827. x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
  828. if (operation != null)
  829. {
  830. operation.FinishedOn = DateTime.UtcNow;
  831. operation.Status = 1;//電樁有回覆
  832. operation.EVSE_Status = 1;
  833. operation.EVSE_Value = JsonConvert.SerializeObject(_confirm.configurationKey, Formatting.None);
  834. }
  835. db.SaveChanges();
  836. }
  837. }
  838. catch (Exception ex)
  839. {
  840. logger.Error(ex.ToString());
  841. }
  842. }
  843. break;
  844. case Actions.UnlockConnector:
  845. {
  846. UnlockConnectorConfirmation _confirm = confirm as UnlockConnectorConfirmation;
  847. UnlockConnectorRequest _request = _confirm.GetRequest() as UnlockConnectorRequest;
  848. using (var db = new MainDBContext())
  849. {
  850. var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
  851. x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
  852. if (operation != null)
  853. {
  854. operation.FinishedOn = DateTime.UtcNow;
  855. operation.Status = 1;//電樁有回覆
  856. operation.EVSE_Status = (int)_confirm.status;
  857. operation.EVSE_Value = _confirm.status.ToString();
  858. db.SaveChanges();
  859. }
  860. }
  861. }
  862. break;
  863. default:
  864. {
  865. Console.WriteLine(string.Format("Not Implement {0} Logic(ExecuteCoreConfirm)", confirm.GetType().ToString().Replace("OCPPPackage.Messages.Core.", "")));
  866. }
  867. break;
  868. }
  869. }
  870. catch (Exception ex)
  871. {
  872. logger.Debug("123 " + ex.ToString());
  873. }
  874. return result;
  875. }
  876. internal MessageResult ReceivedCoreError(Actions action, string errorMsg, ClientData session, string requestId)
  877. {
  878. MessageResult result = new MessageResult() { Success = true };
  879. switch (action)
  880. {
  881. case Actions.ChangeAvailability:
  882. case Actions.ChangeConfiguration:
  883. case Actions.ClearCache:
  884. case Actions.RemoteStartTransaction:
  885. case Actions.RemoteStopTransaction:
  886. case Actions.Reset:
  887. case Actions.GetConfiguration:
  888. case Actions.UnlockConnector:
  889. case Actions.DataTransfer:
  890. {
  891. if (action == Actions.DataTransfer)
  892. {
  893. logger.Debug(string.Format("DataTransfer Error {0}: {1}", session.ChargeBoxId, requestId));
  894. }
  895. using (var db = new MainDBContext())
  896. {
  897. var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
  898. x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
  899. if (operation != null)
  900. {
  901. operation.FinishedOn = DateTime.UtcNow;
  902. operation.Status = 1;//電樁有回覆
  903. operation.EVSE_Status = (int)255;//錯誤
  904. operation.EVSE_Value = errorMsg;
  905. db.SaveChanges();
  906. }
  907. }
  908. }
  909. break;
  910. default:
  911. {
  912. Console.WriteLine(string.Format("Not Implement {0} Logic(ReceivedCoreError)", action));
  913. }
  914. break;
  915. }
  916. return result;
  917. }
  918. /// <summary>
  919. /// 依據幣值處理4捨5入
  920. /// </summary>
  921. /// <param name="money"></param>
  922. /// <param name="currency"></param>
  923. /// <returns></returns>
  924. private decimal DollarRounding(decimal money, string currency)
  925. {
  926. if (currency == "USD" || currency == "EUR")
  927. {
  928. //0.4867
  929. if ((double)((int)(money * 100) + 0.5) <= (double)(money * 100))
  930. {
  931. //money = Decimal.Add(money, (decimal)0.01);//0.4967
  932. }
  933. money = Math.Round(money, 2, MidpointRounding.AwayFromZero);
  934. money = Decimal.Parse(money.ToString("0.00"));
  935. }
  936. else
  937. {
  938. if ((double)((int)(money) + 0.5) <= (double)money)
  939. {
  940. // money = (int) money + 1;
  941. }
  942. money = Math.Round(money, 0, MidpointRounding.AwayFromZero);
  943. money = Decimal.Parse(money.ToString("0"));
  944. }
  945. return money;
  946. }
  947. }
  948. }