WebSocketCommandService.cs 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
  1. using Evcb.Domain.Model;
  2. using Evcb.Repository;
  3. using Evcb.Service;
  4. using Evcb.Service.Helpers;
  5. using Evcb.Service.Service.Common;
  6. using Newtonsoft.Json;
  7. using NLog;
  8. using OCPP_Packet.Packet.DataTransfer;
  9. using OCPP_Packet.Packet.Status;
  10. using System;
  11. using System.Collections.Generic;
  12. using System.Linq;
  13. using System.Text;
  14. using System.Threading.Tasks;
  15. namespace OCPPServer.Service
  16. {
  17. public class WebSocketCommandService : Service<Machine>
  18. {
  19. private ILogger logger = NLog.LogManager.GetCurrentClassLogger();
  20. private readonly IRepository<ChargingRecordStatus> _chargingRecordStatusRepo;
  21. private readonly IRepository<MachineGun> _machineGunRepo;
  22. private readonly IRepository<ChargingRecord> _chargingRecordRepo;
  23. private readonly IRepository<ChargingRecordReport> _chargingRecordReportRepo;
  24. private readonly IRepository<MachineError> _meRepo;
  25. private readonly IRepository<MemberCharging> _memberChargingRepo;
  26. public WebSocketCommandService(IUnitOfWork uow) : base(uow)
  27. {
  28. _uow = uow;
  29. _chargingRecordRepo = _uow.Repository<ChargingRecord>();
  30. _machineGunRepo = _uow.Repository<MachineGun>();
  31. _chargingRecordStatusRepo = _uow.Repository<ChargingRecordStatus>();
  32. _chargingRecordReportRepo = _uow.Repository<ChargingRecordReport>();
  33. _meRepo = _uow.Repository<MachineError>();
  34. _memberChargingRepo = _uow.Repository<MemberCharging>();
  35. }
  36. public ProcessStatusPacketResult Process1104(ChargingRecordStatus value)
  37. {
  38. ProcessStatusPacketResult result = new ProcessStatusPacketResult() { StartChargingType = -1 };
  39. var gun = _machineGunRepo.Query(c => c.GunSerNo == value.GunSerNo && c.Machine.Id == value.MachineId).Include(c => c.Machine).Include(c => c.Machine.Customer).Select().FirstOrDefault();
  40. value.CreatedOn = DateTime.Now;
  41. logger.Trace(value.MachineCustomId + "進入104處理");
  42. if (gun != null)
  43. {
  44. //舊的充電序號
  45. Guid oldGuid = Guid.Empty;
  46. //狀態改變,更換序號
  47. if ((gun.Status == 2 || gun.Status == 3) && (value.Status == 2 || value.Status == 3))
  48. {
  49. //2跟3算同一個狀態 For AC,不更換序號
  50. }
  51. else if (gun.Status != value.Status)
  52. {
  53. oldGuid = gun.ChargingSerNo;
  54. gun.ChargingSerNo = Guid.NewGuid();
  55. }
  56. //從正準備開始充電轉換到充電進行中,新增一筆充電紀錄
  57. //if (((gun.Status == 1 || gun.Status == 0) && value.Status == 2) || ((gun.Status == 1 || gun.Status == 0) && value.Status == 3))
  58. if (value.Status == 2)
  59. {
  60. //DateTime sDate = value.StartChargingDateTime.Value.AddMilliseconds(-1);
  61. //DateTime eDate = value.StartChargingDateTime.Value.AddMilliseconds(3);
  62. ChargingRecord nObj = _chargingRecordRepo.Query(
  63. // c => c.StartChargingDateTime >= sDate
  64. //&& c.StartChargingDateTime <= eDate
  65. c => c.StartChargingDateTime == value.StartChargingDateTime.Value
  66. && c.GunSerNo == value.GunSerNo
  67. && c.MachineId == gun.MachineId).Select().FirstOrDefault();
  68. //沒有該筆充電序才去產生帳單紀錄
  69. if (nObj == null && value.StartChargingDateTime.HasValue)
  70. {
  71. gun.ChargingSerNo = Guid.NewGuid();
  72. nObj = new ChargingRecord()
  73. {
  74. StartChargingDateTime = value.StartChargingDateTime.Value,
  75. StartWith = value.StartWith,
  76. GunSerNo = gun.GunSerNo,
  77. MachineId = gun.Machine.Id,
  78. MachineCustomId = gun.Machine.CustomId,
  79. ChargingSerNo = gun.ChargingSerNo,
  80. ChargingStrategy = value.ChargingStrategy,
  81. ChargingStrategyParam = (int)value.ChargingStrategyParam,
  82. CreatedOn = DateTime.Now
  83. };
  84. _chargingRecordRepo.Add(nObj);
  85. logger.Trace(gun.Machine.CustomId + "開始充電轉換到充電進行中");
  86. logger.Trace("nObj:" + JsonConvert.SerializeObject(nObj));
  87. logger.Trace("value:" + JsonConvert.SerializeObject(value));
  88. //如果每筆記錄都要回報
  89. if (gun.Machine.Customer.AutoCreateReportRecord)
  90. {
  91. //如果是卡片充電的話
  92. if (value.StartWith == 1)
  93. {
  94. logger.Trace("卡片充電:");
  95. ChargingRecordReport rr = new ChargingRecordReport()
  96. {
  97. StartChargingDateTime = value.StartChargingDateTime.Value,
  98. MachineId = nObj.MachineId,
  99. MachineCustomId = nObj.MachineCustomId,
  100. CardNum = value.ReservationCardNum,
  101. StartWith = value.StartWith,
  102. ChargingSerNo = nObj.ChargingSerNo,
  103. CustomerId = gun.Machine.CustomerId,
  104. GunSerNo = value.GunSerNo,
  105. //ChargeStrategy = 2,
  106. ChargeStrategy = value.ChargingStrategy,
  107. ChargeStrategyParam = value.CardBalanceBeforeCharging,
  108. CreatedOn = DateTime.Now,
  109. };
  110. logger.Trace("rr:" + JsonConvert.SerializeObject(rr));
  111. _chargingRecordReportRepo.Add(rr);
  112. result.StartChargingType = 0;
  113. result.ChargingSerNo = rr.ChargingSerNo;
  114. result.Result = 12;
  115. }
  116. }
  117. }
  118. }
  119. //發出一個新的告警,就紀錄到table中
  120. if (value.Status == 6)
  121. {
  122. var hasSameError = _uow.Repository<MachineError>().Query(c => c.MachineId == value.MachineId && c.GunSerNo == gun.GunSerNo).Select().OrderByDescending(c => c.CreatedOn).FirstOrDefault();
  123. MachineError me = new MachineError { CreatedOn = DateTime.Now, MachineId = gun.MachineId, PreStatus = gun.Status, Status = value.Status, ErrorCode = value.Warning, GunSerNo = gun.GunSerNo };
  124. if (gun.Status != 6)
  125. {
  126. // Gun previous status is other status
  127. if (hasSameError != null)
  128. {
  129. if (((value.Warning == hasSameError.ErrorCode) && ((value.CreatedOn - hasSameError.CreatedOn).Value.TotalMinutes > 3)) || (value.Warning != hasSameError.ErrorCode))
  130. {
  131. _meRepo.Add(me);
  132. NoticeError(me);
  133. }
  134. }
  135. else
  136. {
  137. _meRepo.Add(me);
  138. NoticeError(me);
  139. }
  140. }
  141. else
  142. {
  143. // Gun previous status is alarm status
  144. if (value.Warning != hasSameError.ErrorCode)
  145. {
  146. _meRepo.Add(me);
  147. NoticeError(me);
  148. }
  149. //logger.Trace("value.CreatedOn - hasSameError.CreatedOn=" + (value.CreatedOn - hasSameError.CreatedOn).Value.TotalMinutes.ToString());
  150. }
  151. }
  152. ////從充電中,切換狀態到充電結束
  153. //if (gun.Status == 2 && value.Status == 3)
  154. //{
  155. // var chargingRecordObj = _chargingRecordRepo.Query(c => c.ChargingSerNo == oldGuid).Select().FirstOrDefault();
  156. // chargingRecordObj.EndChargingDateTime = DateTime.Now;
  157. // _chargingRecordRepo.Update(chargingRecordObj);
  158. //}
  159. gun.Status = value.Status;
  160. value.ChargingSerNo = gun.ChargingSerNo;
  161. //value.CreatedOn = DateTime.Now;
  162. _chargingRecordStatusRepo.Add(value);
  163. _uow.SaveChanges();
  164. return result;
  165. }
  166. else
  167. {
  168. throw new ApplicationException("wrong guns!");
  169. }
  170. }
  171. private IResult NoticeError(MachineError error)
  172. {
  173. IResult result = new Result();
  174. try
  175. {
  176. string description = "None";
  177. var machineRepo = _uow.Repository<Machine>();
  178. var machine = machineRepo.Query(c => c.Id == error.MachineId).Include(c => c.Customer).Select().FirstOrDefault();
  179. var accountRepo = _uow.Repository<Account>();
  180. var account = accountRepo.Query(c => c.CustomerId == machine.CustomerId).Select().FirstOrDefault();
  181. var errorRepo = _uow.Repository<ErrorCode>();
  182. var errorMsg = errorRepo.Query(c => c.Code == error.ErrorCode).Select().FirstOrDefault();
  183. if (errorMsg != null)
  184. {
  185. if (errorMsg.AC == machine.AC)
  186. {
  187. description = errorMsg.Description;
  188. }
  189. }
  190. if (!string.IsNullOrEmpty(account.Email))
  191. {
  192. string[] emailgroup = account.Email.Split(',');
  193. string subject = string.Format("客户: {0} 飞宏电桩号: {1} 客户电桩号: {2} 错误代码:{3}", machine.Customer.CustomerDesc, machine.CustomId, machine.PartnerPoleId, error.ErrorCode);
  194. string detail = string.Format("[时间点: {0}] 飞宏电桩号: {1} 客户电桩号: {2},枪号 : {3},错误代码: {4} 说明: {5}", error.CreatedOn, machine.CustomId, machine.PartnerPoleId, Convert.ToChar(65 + error.GunSerNo), error.ErrorCode, description);
  195. string body = string.Format("详细讯息: {2} ", machine.PartnerPoleId, error.ErrorCode, detail);
  196. foreach (var email in emailgroup)
  197. {
  198. DispatchMessageHelper.SendMail(email, subject, body);
  199. }
  200. }
  201. result.Success = true;
  202. return result;
  203. }
  204. catch (Exception ex)
  205. {
  206. logger.Error(ex);
  207. result.Exception = ex;
  208. result.Success = false;
  209. return result;
  210. }
  211. }
  212. /// <summary>
  213. /// 處理經緯度
  214. /// </summary>
  215. /// <param name="machineId">電樁Id</param>
  216. /// <param name="Location">Location command</param>
  217. /// <returns></returns>
  218. public IResult ProcessLocation(string customId, Location value)
  219. {
  220. IResult result = new Result();
  221. double radius = 0.005d;
  222. try
  223. {
  224. var machineRepo = _uow.Repository<Machine>();
  225. var _chargerStationRepo = _uow.Repository<ChargerStation>();
  226. var machine = machineRepo.Query(c => c.CustomId == customId).Select().FirstOrDefault();
  227. var stations = _chargerStationRepo.Query(c => c.CustomerId == machine.CustomerId).Select().ToList();
  228. //Mapping 充電樁的位置 以資料庫列表中充電樁站點為圓心,判斷上報的充電樁位置是否在附近
  229. //以0.005d為半徑 超出者預設 0
  230. //double KeyX = 0d, KeyY = 0d;
  231. bool isNearAnyStation = false;
  232. foreach (var station in stations)
  233. {
  234. double YDist = Convert.ToDouble(station.Latitude - Convert.ToDecimal(value.latitude));
  235. double XDist = Convert.ToDouble(station.Longitude - Convert.ToDecimal(value.longitude));
  236. if (Math.Pow(XDist, 2d) + Math.Pow(YDist, 2d) <= Math.Pow(radius, 2d))
  237. {
  238. isNearAnyStation = true;
  239. if (machine.Location != station.Id)
  240. {
  241. machine.Location = station.Id;
  242. }
  243. }
  244. }
  245. if (!isNearAnyStation & machine.Location != 0)
  246. {
  247. machine.Location = 0;
  248. }
  249. _uow.SaveChanges();
  250. result.Success = true;
  251. return result;
  252. }
  253. catch (Exception ex)
  254. {
  255. logger.Error(ex);
  256. result.Exception = ex;
  257. result.Success = false;
  258. return result;
  259. }
  260. }
  261. /// <summary>
  262. /// 處理BMS訊息
  263. /// </summary>
  264. /// <param name="machineId">電樁Id</param>
  265. /// <param name="ChargingGunBMS">ChargingGunBMS command</param>
  266. /// <returns></returns>
  267. public IResult ProcessChargingGunBMS(string machineId, ChargingGunBMS cmd)
  268. {
  269. IResult result = new Result();
  270. var _machineGunRepo = _uow.Repository<MachineGun>();
  271. var _chargingRecordBMSRepo = _uow.Repository<ChargingRecordBMS>();
  272. try
  273. {
  274. var chargingSerNo = _machineGunRepo.Query(x => x.MachineId == machineId && x.GunSerNo == cmd.connectorId && x.Status != 0).Select(x => x.ChargingSerNo).FirstOrDefault();
  275. if (chargingSerNo == null) chargingSerNo = Guid.Empty;
  276. _chargingRecordBMSRepo.Add(new ChargingRecordBMS()
  277. {
  278. MachineId = machineId,
  279. MachineCustomId = _repository.Query(x => x.Id == machineId).Select(x => x.PartnerPoleId).FirstOrDefault(),
  280. GunSerNo = Convert.ToByte(cmd.connectorId-1),
  281. ChargingSerNo = chargingSerNo == null ? Guid.Empty : chargingSerNo,
  282. Status = Convert.ToByte(cmd.status),
  283. CarConnection = Convert.ToByte(cmd.carConnectionStatus),
  284. BRMBMS_ProtocolVersion = cmd.brm_bmsVersion,
  285. BR_BatteryType = Convert.ToByte(cmd.br_BatteryType),
  286. BRM_CarBattery_SystemRatedCurrent = Convert.ToDecimal(cmd.brm_BatterySystemRatedcapacity),
  287. BRM_CarBattery_SystemRatedVoltage = Convert.ToDecimal(cmd.brm_BatterySystemRatedVoltage),
  288. BRM_BatteryManufacturer = cmd.brm_BatteryManufacturer,
  289. BRM_BatteryGroupSN = cmd.brm_BatteryNumber,
  290. BRM_BatteryGroupProductionDate = cmd.brm_ProductionDate,
  291. BRM_BatteryGroupChargingTimes = cmd.brm_BatteryChargeTimes,
  292. BRM_BatteryGroupPropertyRight = Convert.ToByte(cmd.brm_BatteryPropertySign),
  293. BRM_Reserve = Convert.ToByte(cmd.brm_Reserved),
  294. BRM_VIN = cmd.brm_Vin,
  295. BRMBMS_SoftwareVersion = cmd.brm_bmsSoftwareVersion,
  296. BCP_SingleBatteryAllowChargeMaxVoltage = Convert.ToDecimal(cmd.bcp_SingleBatteryHightestChargeVoltage),
  297. BCP_AllowChargeMaxCurrent = Convert.ToDecimal(cmd.bcp_HightestChargeCurrent),
  298. BCP_BatteryFlagTotalEnergy = Convert.ToDecimal(cmd.bcp_BatteryLabelingTotalEnergy),
  299. BCP_AllowChargeMaxTotalVoltage = Convert.ToDecimal(cmd.bcp_HightestChargeVoltage),
  300. BCP_AllowHighestTemperature = cmd.bcp_HightestTemperature,
  301. BCP_CarBatterySOC = Convert.ToDecimal(cmd.bcp_VehiclePowerBatteryChargeState),
  302. BCP_CarBatteryCurrentBatteryVoltage = Convert.ToDecimal(cmd.bcp_VehicleBatteryCurrentVoltage),
  303. BROBMS_IsReadyCharge = Convert.ToByte((cmd.bro_bms_ChargeReadyStatus == ChargeReadyStatus.NotReady) ? 0x00 : ((cmd.bro_bms_ChargeReadyStatus == ChargeReadyStatus.Ready) ? 0xAA : 0xFF)),
  304. BCL_Voltage = Convert.ToDecimal(cmd.bcl_DemandVoltage),
  305. BCL_Current = Convert.ToDecimal(cmd.bcl_DemandCurrent),
  306. BCL_ChargeMode = Convert.ToByte(cmd.bcl_ChargeMode),
  307. BCS_ChargeVotageMeasurement = Convert.ToDecimal(cmd.bcs_ChargeVoltageMeasurement),
  308. BCS_ChargeCurrentMeasurement = Convert.ToDecimal(cmd.bcs_ChargeCurrentMeasurement),
  309. BCS_SingleBatteryMaxVoltage = Convert.ToDecimal(cmd.bcs_HightestSingleBatteryVoltage),
  310. BCS_SingleBatteryGroupNumber = cmd.bcs_HightestSingleBatteryNumber,
  311. BCS_CurrentSOC = Convert.ToByte(cmd.bcs_CurrentSOC),
  312. RemainingChargeMins = cmd.remainingChargeTime,
  313. BSM_SingleBatteryMaxVoltageNumber = cmd.bsm_HightestSingleBatteryVoltageNumber,
  314. BSM_BatteryHighestTemperature = cmd.bsm_HightestBatteryTemperature,
  315. BSM_HighestTemperatureCheckPointNumber = cmd.bsm_HightestTemperatureDetectionPointNumber,
  316. BSM_BatteryLowestTemperature = cmd.bsm_LowestBatteryTemperature,
  317. BSM_LowestTemperatureCheckPointNumber = cmd.bsm_LowestTemperatureDetectionPointNumber,
  318. BSM_SingleBatteryVoltageStatus = Convert.ToByte((cmd.bsm_SingleBatteryVoltageStatus == BMSStatusAType.Normal) ? 0x00 : ((cmd.bsm_SingleBatteryVoltageStatus == BMSStatusAType.TooHigh) ? 0x01 : 0x10)),
  319. BSM_CarBatterySOCStatus = Convert.ToByte((cmd.bsm_VehicleBatterySOCStatus == BMSStatusAType.Normal) ? 0x00: ((cmd.bsm_VehicleBatterySOCStatus == BMSStatusAType.TooHigh) ? 0x01 : 0x10)),
  320. BSM_BatteryChargineCurrentStatus = Convert.ToByte((cmd.bsm_BatteryChargeCurrentStatus == BMSStatusBType.Normal) ? 0x00 : ((cmd.bsm_BatteryChargeCurrentStatus == BMSStatusBType.TooHigh) ? 0x01 : 0x10)),
  321. BSM_BatteryTemperatureTooHigh = Convert.ToByte((cmd.bsm_BatteryTemperatureStatus == BMSStatusBType.Normal) ? 0x00 : ((cmd.bsm_BatteryTemperatureStatus == BMSStatusBType.TooHigh) ? 0x01 : 0x10)),
  322. BSM_BatteryInsulationStatus = Convert.ToByte((cmd.bsm_BatteryInsulationStatus == BMSStatusBType.Normal) ? 0x00 : ((cmd.bsm_BatteryInsulationStatus == BMSStatusBType.TooHigh) ? 0x01 : 0x10)),
  323. BSM_BatteryOutputConnectionStatus = Convert.ToByte((cmd.bsm_BatteryOutputConnectorConnectionStatus == BMSStatusBType.Normal) ? 0x00 : ((cmd.bsm_BatteryOutputConnectorConnectionStatus == BMSStatusBType.TooHigh) ? 0x01 : 0x10)),
  324. BSM_AllowCharge = Convert.ToByte((cmd.bsm_IsAllowedCharge == false) ? 0x00 : 0x01),
  325. BSTBMS_SOCGoal = Convert.ToByte((cmd.bst_bms_IsAchievedSOCTargetStatus == BMSStatusCType.Below) ? 0x00 : ((cmd.bst_bms_IsAchievedSOCTargetStatus == BMSStatusCType.Standard) ? 0x01 : 0x10)),
  326. BSTBMS_TotalVotageSetting = Convert.ToByte((cmd.bst_bms_IsAchievedSettingTotalVoltageStatus == BMSStatusCType.Below) ? 0x00 : ((cmd.bst_bms_IsAchievedSettingTotalVoltageStatus == BMSStatusCType.Standard) ? 0x01 : 0x10)),
  327. BST_SingleVotageSetting = Convert.ToByte((cmd.bst_IsAchievedSettingSingleVoltageStatus == BMSStatusCType.Below) ? 0x00 : ((cmd.bst_IsAchievedSettingSingleVoltageStatus == BMSStatusCType.Standard) ? 0x01 : 0x10)),
  328. BST_ChargerActiveStop = Convert.ToByte((cmd.bst_chargerAutoTerminationStatus == ChargerAutoTerminationStatus.Normal) ? 0x00 : ((cmd.bst_chargerAutoTerminationStatus == ChargerAutoTerminationStatus.ChargerIsTerminated) ? 0x01 : 0x10)),
  329. BST_InsulationError = Convert.ToByte((cmd.bst_InsulationFaultStatus == BMSStatusDType.Normal) ? 0x00 : ((cmd.bst_InsulationFaultStatus == BMSStatusDType.Fault) ? 0x01 : 0x10)),
  330. BST_OutputConnectionOverTemperatureError = Convert.ToByte((cmd.bst_OutputConnectorTemperatureStatus == BMSStatusDType.Normal) ? 0x00 : ((cmd.bst_OutputConnectorTemperatureStatus == BMSStatusDType.Fault) ? 0x01 : 0x10)),
  331. BSTBMSComponent_OutputConnectionOverTemperatureError = Convert.ToByte((cmd.bst_bms_OutputConnectorTemperatureStatus == BMSStatusDType.Normal) ? 0x00 : ((cmd.bst_bms_OutputConnectorTemperatureStatus == BMSStatusDType.Fault) ? 0x01 : 0x10)),
  332. BST_ChargeConnectionError = Convert.ToByte((cmd.bst_chargerConnectorStatus == BMSStatusBType.Normal) ? 0x00 : ((cmd.bst_chargerConnectorStatus == BMSStatusBType.TooHigh) ? 0x01 : 0x10)),
  333. BST_BatteryGroupOverTemperatureError = Convert.ToByte((cmd.bst_BatteryTemperatureStatus == BMSStatusBType.Normal) ? 0x00 : ((cmd.bst_BatteryTemperatureStatus == BMSStatusBType.TooHigh) ? 0x01 : 0x10)),
  334. BST_HighVoltageRelayError = Convert.ToByte((cmd.bst_HighVoltageRelayStatus == BMSStatusBType.Normal) ? 0x00 : ((cmd.bst_HighVoltageRelayStatus == BMSStatusBType.TooHigh) ? 0x01 : 0x10)),
  335. BST_Checkponit2VoltageCheckError = Convert.ToByte((cmd.bst_DetectionPoint2Voltage == BMSStatusBType.Normal) ? 0x00 : ((cmd.bst_DetectionPoint2Voltage == BMSStatusBType.TooHigh) ? 0x01 : 0x10)),
  336. BST_OtherError = Convert.ToByte((cmd.bst_Other == BMSStatusBType.Normal) ? 0x00 : ((cmd.bst_Other == BMSStatusBType.TooHigh) ? 0x01 : 0x10)),
  337. BST_OverCurrent = Convert.ToByte((cmd.bst_Current == BMSStatusBType.Normal) ? 0x00 : ((cmd.bst_Current == BMSStatusBType.TooHigh) ? 0x01 : 0x10)),
  338. BST_VoltageError = Convert.ToByte((cmd.bst_Voltage == BMSStatusBType.Normal) ? 0x00 : ((cmd.bst_Voltage == BMSStatusBType.TooHigh) ? 0x01 : 0x10)),
  339. BSD_StopSOC = Convert.ToByte(cmd.bsd_EndSOC),
  340. BSD_SingleBatteryLowestVoltage = Convert.ToDecimal(cmd.bsd_SingleBatteryLowestVoltage),
  341. BSD_SingleBatteryHighestVoltage = Convert.ToDecimal(cmd.bsd_SingleBatteryHightestVoltage),
  342. BSD_BatteryLowestTemperature = cmd.bsd_BatteryLowestTemperature,
  343. BSD_BatteryHighestTemperature = cmd.bsd_BatteryHightestTemperature,
  344. BEM_ReceivedSPN2560_0x00 = Convert.ToByte((cmd.bem_ReceivedSPN2560_00_Status == BMSStatusEType.Normal) ? 0x00 : ((cmd.bem_ReceivedSPN2560_00_Status == BMSStatusEType.TimeOut) ? 0x01 : 0x10)),
  345. BEM_ReceivedSPN2560_0xAA = Convert.ToByte((cmd.bem_ReceivedSPN2560_aa_Status == BMSStatusEType.Normal) ? 0x00 : ((cmd.bem_ReceivedSPN2560_aa_Status == BMSStatusEType.TimeOut) ? 0x01 : 0x10)),
  346. BEM_ReceivedSyncAndMaxOutputPower_Timeout = Convert.ToByte((cmd.bem_ReceivedTimeSyncAndMaxOutputStatus == BMSStatusEType.Normal) ? 0x00 : ((cmd.bem_ReceivedTimeSyncAndMaxOutputStatus == BMSStatusEType.TimeOut) ? 0x01 : 0x10)),
  347. BEM_ReceivedReadyCharge_Timeout = Convert.ToByte((cmd.bem_ReceivedReadyMessageStatus == BMSStatusEType.Normal) ? 0x00 : ((cmd.bem_ReceivedReadyMessageStatus == BMSStatusEType.TimeOut) ? 0x01 : 0x10)),
  348. BEM_ReceivedChargerStatus_Timeout = Convert.ToByte((cmd.bem_ReceivedStatusMessageStatus == BMSStatusEType.Normal) ? 0x00 : ((cmd.bem_ReceivedStatusMessageStatus == BMSStatusEType.TimeOut) ? 0x01 : 0x10)),
  349. BEM_ReceivedChargerStopCharge_Timeout = Convert.ToByte((cmd.bem_ReceivedStopMessageStatus == BMSStatusEType.Normal) ? 0x00 : ((cmd.bem_ReceivedStopMessageStatus == BMSStatusEType.TimeOut) ? 0x01 : 0x10)),
  350. BEM_ReceivedChargerChargeStatistics_Timeout = Convert.ToByte((cmd.bem_ReceivedStatisticsMessageStatus == BMSStatusEType.Normal) ? 0x00 : ((cmd.bem_ReceivedStatisticsMessageStatus == BMSStatusEType.TimeOut) ? 0x01 : 0x10)),
  351. BEM_Other = Convert.ToByte(cmd.bem_Other),
  352. CreateOn = DateTime.Now
  353. });
  354. _uow.SaveChanges();
  355. result.Success = true;
  356. }
  357. catch (Exception ex)
  358. {
  359. result.Exception = ex;
  360. result.Message = ex.Message;
  361. }
  362. return result;
  363. }
  364. /// <summary>
  365. /// 處理ChargeComplete
  366. /// </summary>
  367. /// <param name="value">ChargeComplete command</param>
  368. /// <param name="MachineCustomId">電樁樁號</param>
  369. /// <returns></returns>
  370. public IResult ProcessChargeComplete(ChargeComplete value, string MachineCustomId)
  371. {
  372. IResult result = new Result();
  373. var _chargingRecordRepo = _uow.Repository<ChargingRecord>();
  374. var crrRepo = _uow.Repository<ChargingRecordReport>();
  375. var machineRepo = _uow.Repository<Machine>();
  376. try
  377. {
  378. var machine = machineRepo.Query(c => c.CustomId == MachineCustomId).Select().FirstOrDefault();
  379. var chargingTransaction = _uow.Repository<ChargingTransaction>().Query(c => c.TransactionId == value.transactionId).Select().FirstOrDefault();
  380. if(chargingTransaction == null)
  381. {
  382. result.Success = false;
  383. result.Message = "No Transaction Id";
  384. return result;
  385. }
  386. var record = _chargingRecordRepo.Query(c => c.Id == chargingTransaction.ChargingRecordId).Select().FirstOrDefault();
  387. //沒有資料就補上去
  388. bool isNew = false;
  389. if (record == null)
  390. {
  391. record = new ChargingRecord();
  392. record.MachineId = machine.Id;
  393. record.MachineCustomId = machine.CustomId;
  394. record.GunSerNo = (byte)(value.connectorId-1);
  395. record.ChargingSerNo = Guid.NewGuid();
  396. record.StartChargingDateTime = value.startChargingDateTime;//value.startChargingDateTime.ToLocalTime();
  397. record.EndChargingDateTime = value.chargeCompleteDateTime;//value.chargeCompleteDateTime.ToLocalTime();
  398. record.CreatedOn = DateTime.Now;
  399. isNew = true;
  400. }
  401. #region Mapper
  402. record.CumulativeKwh = (decimal)value.cumulativeKwh;
  403. record.KwhBeforeCharging = (decimal)value.beforeChargingKwh;
  404. record.KwhAfterCharging = (decimal)value.chargeCompleteKwh;
  405. record.ElectricBill = Decimal.Multiply((decimal)value.cumulativeKwh, machine.PricePerKWH);//(decimal)value.electricBill;
  406. record.FeeAmount = Decimal.Multiply((decimal)value.cumulativeKwh, machine.FeePerKWH);//(decimal)value.feeAmount;
  407. record.SumOfMoney = record.ElectricBill + record.FeeAmount;
  408. record.StopChargingReason = (int)value.reason;
  409. record.StartWith = (byte)value.startWith;
  410. record.StartSoc = (byte)value.startChargingSOC;
  411. record.StartChargingType = (byte)value.startChargingType;
  412. record.PayOffline = (byte)(value.isPayOffline ? 1 : 0);
  413. record.EndSoc = (byte)value.chargeCompleteSOC;
  414. record.ChargingStrategyParam = (int)value.chargingStrategyParameter;
  415. record.ChargingStrategy = (byte)value.chargingStrategy;
  416. record.CarNum = value.licensePlateNumber;
  417. record.CardVIN = value.vinCode;
  418. record.CardBalanceBeforeCharging = (decimal)value.cardBalanceBeforeCharging;
  419. record.CardBalanceAfterCharging = (decimal)value.cardBalanceAfterCharging;
  420. record.Time1 = (decimal)value.sectionKwh[0];
  421. record.Time2 = (decimal)value.sectionKwh[1];
  422. record.Time3 = (decimal)value.sectionKwh[2];
  423. record.Time4 = (decimal)value.sectionKwh[3];
  424. record.Time5 = (decimal)value.sectionKwh[4];
  425. record.Time6 = (decimal)value.sectionKwh[5];
  426. record.Time7 = (decimal)value.sectionKwh[6];
  427. record.Time8 = (decimal)value.sectionKwh[7];
  428. record.Time9 = (decimal)value.sectionKwh[8];
  429. record.Time10 = (decimal)value.sectionKwh[9];
  430. record.Time11 = (decimal)value.sectionKwh[10];
  431. record.Time12 = (decimal)value.sectionKwh[11];
  432. record.Time13 = (decimal)value.sectionKwh[12];
  433. record.Time14 = (decimal)value.sectionKwh[13];
  434. record.Time15 = (decimal)value.sectionKwh[14];
  435. record.Time16 = (decimal)value.sectionKwh[15];
  436. record.Time17 = (decimal)value.sectionKwh[16];
  437. record.Time18 = (decimal)value.sectionKwh[17];
  438. record.Time19 = (decimal)value.sectionKwh[18];
  439. record.Time20 = (decimal)value.sectionKwh[19];
  440. record.Time21 = (decimal)value.sectionKwh[20];
  441. record.Time22 = (decimal)value.sectionKwh[21];
  442. record.Time23 = (decimal)value.sectionKwh[22];
  443. record.Time24 = (decimal)value.sectionKwh[23];
  444. record.Time25 = (decimal)value.sectionKwh[24];
  445. record.Time26 = (decimal)value.sectionKwh[25];
  446. record.Time27 = (decimal)value.sectionKwh[26];
  447. record.Time28 = (decimal)value.sectionKwh[27];
  448. record.Time29 = (decimal)value.sectionKwh[28];
  449. record.Time30 = (decimal)value.sectionKwh[29];
  450. record.Time31 = (decimal)value.sectionKwh[30];
  451. record.Time32 = (decimal)value.sectionKwh[31];
  452. record.Time33 = (decimal)value.sectionKwh[32];
  453. record.Time34 = (decimal)value.sectionKwh[33];
  454. record.Time35 = (decimal)value.sectionKwh[34];
  455. record.Time36 = (decimal)value.sectionKwh[35];
  456. record.Time37 = (decimal)value.sectionKwh[36];
  457. record.Time38 = (decimal)value.sectionKwh[37];
  458. record.Time39 = (decimal)value.sectionKwh[38];
  459. record.Time40 = (decimal)value.sectionKwh[39];
  460. record.Time41 = (decimal)value.sectionKwh[40];
  461. record.Time42 = (decimal)value.sectionKwh[41];
  462. record.Time43 = (decimal)value.sectionKwh[42];
  463. record.Time44 = (decimal)value.sectionKwh[43];
  464. record.Time45 = (decimal)value.sectionKwh[44];
  465. record.Time46 = (decimal)value.sectionKwh[45];
  466. record.Time47 = (decimal)value.sectionKwh[46];
  467. record.Time48 = (decimal)value.sectionKwh[47];
  468. record.ClientStartChargingDateTime = value.startChargingDateTime;//value.startChargingDateTime.ToLocalTime();
  469. record.ClientEndChargingDateTime = value.chargeCompleteDateTime;//value.chargeCompleteDateTime.ToLocalTime();
  470. if (value.startWith == StartWith.Member)
  471. {
  472. var membertb = _memberChargingRepo.Query(c => c.SelfDefinedId == value.idTag).Select().FirstOrDefault();
  473. if (membertb != null)
  474. {
  475. //會員
  476. record.MemberId = membertb.MemberChargingId.ToString();
  477. }
  478. }
  479. else if ((value.startWith == StartWith.CardNumber) || (value.startWith == StartWith.Unknown))
  480. {
  481. record.CardNum = value.idTag;
  482. }
  483. #endregion Mapper
  484. if (isNew)
  485. _chargingRecordRepo.Add(record);
  486. else
  487. _chargingRecordRepo.Update(record);
  488. //處理傳送給客戶api的紀錄
  489. var report = crrRepo.Query(c => c.ChargingSerNo == record.ChargingSerNo).Select().FirstOrDefault();
  490. if (report == null)
  491. {
  492. report = new ChargingRecordReport();
  493. report.CreatedOn = DateTime.Now;
  494. report.StartChargingDateTime = record.StartChargingDateTime;
  495. report.ChargingSerNo = record.ChargingSerNo;
  496. report.CustomerId = machine.CustomerId;
  497. report.GunSerNo = record.GunSerNo;
  498. report.MachineCustomId = machine.CustomId;
  499. report.MachineId = machine.Id;
  500. report.MemberId = record.MemberId;
  501. report.CardNum = record.CardNum;
  502. report.StartWith = record.StartWith;
  503. report.Time1 = record.Time1;
  504. report.Time2 = record.Time2;
  505. report.Time3 = record.Time3;
  506. report.Time4 = record.Time4;
  507. report.Time5 = record.Time5;
  508. report.Time6 = record.Time6;
  509. report.Time7 = record.Time7;
  510. report.Time8 = record.Time8;
  511. report.Time9 = record.Time9;
  512. report.Time10 = record.Time10;
  513. report.Time11 = record.Time11;
  514. report.Time12 = record.Time12;
  515. report.Time13 = record.Time13;
  516. report.Time14 = record.Time14;
  517. report.Time15 = record.Time15;
  518. report.Time16 = record.Time16;
  519. report.Time17 = record.Time17;
  520. report.Time18 = record.Time18;
  521. report.Time19 = record.Time19;
  522. report.Time20 = record.Time20;
  523. report.Time21 = record.Time21;
  524. report.Time22 = record.Time22;
  525. report.Time23 = record.Time23;
  526. report.Time24 = record.Time24;
  527. report.Time25 = record.Time25;
  528. report.Time26 = record.Time26;
  529. report.Time27 = record.Time27;
  530. report.Time28 = record.Time28;
  531. report.Time29 = record.Time29;
  532. report.Time30 = record.Time30;
  533. report.Time31 = record.Time31;
  534. report.Time32 = record.Time32;
  535. report.Time33 = record.Time33;
  536. report.Time34 = record.Time34;
  537. report.Time35 = record.Time35;
  538. report.Time36 = record.Time36;
  539. report.Time37 = record.Time37;
  540. report.Time38 = record.Time38;
  541. report.Time39 = record.Time39;
  542. report.Time40 = record.Time40;
  543. report.Time41 = record.Time41;
  544. report.Time42 = record.Time42;
  545. report.Time43 = record.Time43;
  546. report.Time44 = record.Time44;
  547. report.Time45 = record.Time45;
  548. report.Time46 = record.Time46;
  549. report.Time47 = record.Time47;
  550. report.Time48 = record.Time48;
  551. report.ChargeStrategy = record.ChargingStrategy;
  552. report.ChargeStrategyParam = record.ChargingStrategyParam;
  553. report.SumOfMoney = record.SumOfMoney;
  554. report.FeeAmount = record.FeeAmount;
  555. report.ElectricBill = record.ElectricBill;
  556. report.StartChargingDateTime = record.ClientStartChargingDateTime;
  557. report.EndChargingDateTime = record.ClientEndChargingDateTime;
  558. report.CumulativeKwh = record.CumulativeKwh;
  559. var ts = report.EndChargingDateTime - report.StartChargingDateTime;
  560. report.TotalUsedTime = Convert.ToInt32(ts.Value.TotalSeconds);
  561. report.CarNum = record.CarNum;
  562. report.StartSoc = record.StartSoc;
  563. report.EndSoc = record.EndSoc;
  564. report.KwhBeforeCharging = record.KwhBeforeCharging;
  565. report.KwhAfterCharging = record.KwhAfterCharging;
  566. report.CardBalanceBeforeCharging = record.CardBalanceBeforeCharging;
  567. report.CardBalanceAfterCharging = record.CardBalanceAfterCharging;
  568. report.PayOffline = record.PayOffline;
  569. report.CardVIN = record.CardVIN;
  570. report.StartChargingType = record.StartChargingType;
  571. report.StopChargingReason = record.StopChargingReason;
  572. report.UpdatedOn = DateTime.Now;
  573. crrRepo.Add(report);
  574. }
  575. else
  576. {
  577. report.MemberId = record.MemberId;
  578. report.CardNum = record.CardNum;
  579. report.StartWith = record.StartWith;
  580. report.Time1 = record.Time1;
  581. report.Time2 = record.Time2;
  582. report.Time3 = record.Time3;
  583. report.Time4 = record.Time4;
  584. report.Time5 = record.Time5;
  585. report.Time6 = record.Time6;
  586. report.Time7 = record.Time7;
  587. report.Time8 = record.Time8;
  588. report.Time9 = record.Time9;
  589. report.Time10 = record.Time10;
  590. report.Time11 = record.Time11;
  591. report.Time12 = record.Time12;
  592. report.Time13 = record.Time13;
  593. report.Time14 = record.Time14;
  594. report.Time15 = record.Time15;
  595. report.Time16 = record.Time16;
  596. report.Time17 = record.Time17;
  597. report.Time18 = record.Time18;
  598. report.Time19 = record.Time19;
  599. report.Time20 = record.Time20;
  600. report.Time21 = record.Time21;
  601. report.Time22 = record.Time22;
  602. report.Time23 = record.Time23;
  603. report.Time24 = record.Time24;
  604. report.Time25 = record.Time25;
  605. report.Time26 = record.Time26;
  606. report.Time27 = record.Time27;
  607. report.Time28 = record.Time28;
  608. report.Time29 = record.Time29;
  609. report.Time30 = record.Time30;
  610. report.Time31 = record.Time31;
  611. report.Time32 = record.Time32;
  612. report.Time33 = record.Time33;
  613. report.Time34 = record.Time34;
  614. report.Time35 = record.Time35;
  615. report.Time36 = record.Time36;
  616. report.Time37 = record.Time37;
  617. report.Time38 = record.Time38;
  618. report.Time39 = record.Time39;
  619. report.Time40 = record.Time40;
  620. report.Time41 = record.Time41;
  621. report.Time42 = record.Time42;
  622. report.Time43 = record.Time43;
  623. report.Time44 = record.Time44;
  624. report.Time45 = record.Time45;
  625. report.Time46 = record.Time46;
  626. report.Time47 = record.Time47;
  627. report.Time48 = record.Time48;
  628. report.CumulativeKwh = record.CumulativeKwh;
  629. report.EndChargingDateTime = record.ClientEndChargingDateTime;
  630. report.StartChargingDateTime = record.ClientStartChargingDateTime;
  631. report.FeeAmount = record.FeeAmount;
  632. report.ElectricBill = record.ElectricBill;
  633. report.SumOfMoney = record.SumOfMoney;
  634. var ts = report.EndChargingDateTime - report.StartChargingDateTime;
  635. report.TotalUsedTime = Convert.ToInt32(ts.Value.TotalSeconds);
  636. report.CarNum = record.CarNum;
  637. report.StartSoc = record.StartSoc;
  638. report.EndSoc = record.EndSoc;
  639. report.KwhBeforeCharging = record.KwhBeforeCharging;
  640. report.KwhAfterCharging = record.KwhAfterCharging;
  641. report.CardBalanceBeforeCharging = record.CardBalanceBeforeCharging;
  642. report.CardBalanceAfterCharging = record.CardBalanceAfterCharging;
  643. report.PayOffline = record.PayOffline;
  644. report.CardVIN = record.CardVIN;
  645. report.StartChargingType = record.StartChargingType;
  646. report.StopChargingReason = record.StopChargingReason;
  647. report.UpdatedOn = DateTime.Now;
  648. }
  649. WarnChargeIsAbnormal(record);
  650. _uow.SaveChanges();
  651. result.Success = true;
  652. return result;
  653. }
  654. catch (Exception ex)
  655. {
  656. logger.Error(ex);
  657. result.Exception = ex;
  658. result.Success = false;
  659. return result;
  660. }
  661. }
  662. /// <summary>
  663. /// 通知Email
  664. /// </summary>
  665. /// <param name="machineId">電樁Id</param>
  666. /// <param name="subject">主旨</param>
  667. /// <param name="body">內文</param>
  668. /// <returns></returns>
  669. private IResult NoticeEmail(string machineId, string subject, string body)
  670. {
  671. IResult result = new Result();
  672. try
  673. {
  674. var machineRepo = _uow.Repository<Machine>();
  675. var machine = machineRepo.Query(c => c.Id == machineId).Include(c => c.Customer).Select().FirstOrDefault();
  676. var accountRepo = _uow.Repository<Account>();
  677. var account = accountRepo.Query(c => c.CustomerId == machine.CustomerId).Select().FirstOrDefault();
  678. if (!string.IsNullOrEmpty(account.Email))
  679. {
  680. string[] emailgroup = account.Email.Split(',');
  681. string _subject = string.Format("[{0}] 客户: {1} 飞宏电桩号: {2} 客户电桩号: {3} ", subject, machine.Customer.CustomerDesc, machine.CustomId, machine.PartnerPoleId);
  682. foreach (var email in emailgroup)
  683. {
  684. DispatchMessageHelper.SendMail(email, _subject, body);
  685. }
  686. }
  687. result.Success = true;
  688. return result;
  689. }
  690. catch (Exception ex)
  691. {
  692. logger.Error(ex);
  693. result.Exception = ex;
  694. result.Success = false;
  695. return result;
  696. }
  697. }
  698. /// <summary>
  699. /// 警告充電量異常
  700. /// </summary>
  701. /// <returns></returns>
  702. private IResult WarnChargeIsAbnormal(ChargingRecord record)
  703. {
  704. IResult result = new Result();
  705. try
  706. {
  707. //設定條件-充電時間超過 1800秒 -總充電量小於 0.5kw - StartWith != 2
  708. if (record.CumulativeKwh < Convert.ToDecimal(0.5) && record.ClientEndChargingDateTime.HasValue
  709. && record.ClientStartChargingDateTime.HasValue && record.StartWith != 2)
  710. {
  711. var totalSeconds = record.ClientEndChargingDateTime.Value.Subtract(record.ClientStartChargingDateTime.Value).TotalSeconds;
  712. if (totalSeconds > 1800d)
  713. {
  714. string body = string.Format("详细讯息: 充电序:{0} 充电开始时间:{1} 充电结束时间: {2} 充电秒数:{3} 充电度数:{4}",
  715. record.ChargingSerNo, record.ClientStartChargingDateTime.HasValue ? record.ClientStartChargingDateTime.Value.ToString("yyyy-MM-dd HH:mm:ss") : "None",
  716. record.ClientEndChargingDateTime.HasValue ? record.ClientEndChargingDateTime.Value.ToString("yyyy-MM-dd HH:mm:ss") : "None", totalSeconds, record.CumulativeKwh);
  717. NoticeEmail(record.MachineId, "充电量异常通知", body);
  718. }
  719. }
  720. result.Success = true;
  721. return result;
  722. }
  723. catch (Exception ex)
  724. {
  725. logger.Error(ex);
  726. result.Success = false;
  727. result.Exception = ex;
  728. result.Message = ex.Message;
  729. return result;
  730. }
  731. }
  732. }
  733. }