using EVCB_OCPP.Domain; using EVCB_OCPP.Domain.Models.Database; using EVCB_OCPP.Packet.Features; using EVCB_OCPP.Packet.Messages; using EVCB_OCPP.Packet.Messages.Core; using EVCB_OCPP.Packet.Messages.SubTypes; using EVCB_OCPP.WSServer.Dto; using EVCB_OCPP.WSServer.Service; using Newtonsoft.Json; using NLog; using OCPPPackage.Profiles; using OCPPServer.Protocol; using System; using System.Collections.Generic; using System.Data.Entity; using System.Data.SqlClient; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; namespace EVCB_OCPP.WSServer.Message { internal partial class ProfileHandler { static private ILogger logger = NLog.LogManager.GetCurrentClassLogger(); async internal Task ExecuteCoreRequest(Actions action, ClientData session, IRequest request) { Stopwatch watch = new Stopwatch(); if (action == Actions.Heartbeat) { watch.Start(); } MessageResult result = new MessageResult() { Success = false }; try { switch (action) { case Actions.DataTransfer: { var confirm = new DataTransferConfirmation() { status = DataTransferStatus.Accepted }; result.Message = confirm; result.Success = true; } break; case Actions.BootNotification: { BootNotificationRequest _request = request as BootNotificationRequest; int heartbeat_interval = GlobalConfig.GetHEARTBEAT_INTERVAL(); using (var db = new MainDBContext()) { var _machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault(); _machine.ChargeBoxSerialNumber = string.IsNullOrEmpty(_request.chargeBoxSerialNumber) ? string.Empty : _request.chargeBoxSerialNumber; _machine.ChargePointSerialNumber = string.IsNullOrEmpty(_request.chargePointSerialNumber) ? string.Empty : _request.chargePointSerialNumber; _machine.ChargePointModel = string.IsNullOrEmpty(_request.chargePointModel) ? string.Empty : _request.chargePointModel; _machine.ChargePointVendor = string.IsNullOrEmpty(_request.chargePointVendor) ? string.Empty : _request.chargePointVendor; _machine.FW_CurrentVersion = string.IsNullOrEmpty(_request.firmwareVersion) ? string.Empty : _request.firmwareVersion; //_machine.Iccid = string.IsNullOrEmpty(_request.iccid) ? string.Empty : _request.iccid; _machine.Iccid = DateTime.UtcNow.ToString("yy-MM-dd HH:mm"); _machine.Imsi = string.IsNullOrEmpty(_request.imsi) ? string.Empty : _request.imsi; _machine.MeterSerialNumber = string.IsNullOrEmpty(_request.meterSerialNumber) ? string.Empty : _request.meterSerialNumber; _machine.MeterType = string.IsNullOrEmpty(_request.meterType) ? string.Empty : _request.meterType; db.SaveChanges(); var configVaule = db.MachineConfiguration.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.ConfigureName == StandardConfiguration.HeartbeatInterval) .Select(x => x.ConfigureSetting).FirstOrDefault(); if (configVaule != null) { int.TryParse(configVaule, out heartbeat_interval); } } var confirm = new BootNotificationConfirmation() { currentTime = DateTime.UtcNow, interval = session.IsPending ? heartbeat_interval : 5, status = session.IsPending ? Packet.Messages.SubTypes.RegistrationStatus.Accepted : RegistrationStatus.Pending }; session.IsPending = !session.IsPending; result.Message = confirm; result.Success = true; } break; case Actions.StatusNotification: { //只保留最新上報狀況 StatusNotificationRequest _request = request as StatusNotificationRequest; int preStatus = 0; using (var db = new MainDBContext()) { var _oldStatus = db.ConnectorStatus.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.ConnectorId == _request.connectorId).AsNoTracking().FirstOrDefault(); if (_oldStatus != null && (_request.status != (ChargePointStatus)_oldStatus.Status || _request.status == ChargePointStatus.Faulted)) { preStatus = _oldStatus.Status; db.Configuration.AutoDetectChangesEnabled = false; db.Configuration.ValidateOnSaveEnabled = false; db.ConnectorStatus.Attach(_oldStatus); _oldStatus.CreatedOn = _request.timestamp.HasValue ? _request.timestamp.Value : DateTime.UtcNow; _oldStatus.Status = (int)_request.status; _oldStatus.ChargePointErrorCodeId = (int)_request.errorCode; _oldStatus.ErrorInfo = string.IsNullOrEmpty(_request.info) ? string.Empty : _request.info; _oldStatus.VendorId = string.IsNullOrEmpty(_request.vendorId) ? string.Empty : _request.vendorId; _oldStatus.VendorErrorCode = string.IsNullOrEmpty(_request.vendorErrorCode) ? string.Empty : _request.vendorErrorCode; db.Entry(_oldStatus).Property(x => x.CreatedOn).IsModified = true; db.Entry(_oldStatus).Property(x => x.Status).IsModified = true; db.Entry(_oldStatus).Property(x => x.ChargePointErrorCodeId).IsModified = true; db.Entry(_oldStatus).Property(x => x.ErrorInfo).IsModified = true; db.Entry(_oldStatus).Property(x => x.VendorId).IsModified = true; db.Entry(_oldStatus).Property(x => x.VendorErrorCode).IsModified = true; } if (_oldStatus == null) { var _currentStatus = new Domain.Models.Database.ConnectorStatus() { ChargeBoxId = session.ChargeBoxId, ConnectorId = (byte)_request.connectorId, CreatedOn = _request.timestamp.HasValue ? _request.timestamp.Value : DateTime.UtcNow, Status = (int)_request.status, ChargePointErrorCodeId = (int)_request.errorCode, ErrorInfo = string.IsNullOrEmpty(_request.info) ? string.Empty : _request.info, VendorId = string.IsNullOrEmpty(_request.vendorId) ? string.Empty : _request.vendorId, VendorErrorCode = string.IsNullOrEmpty(_request.vendorErrorCode) ? string.Empty : _request.vendorErrorCode, Id = Guid.NewGuid().ToString() }; db.ConnectorStatus.Add(_currentStatus); } if (_request.status == Packet.Messages.SubTypes.ChargePointStatus.Faulted) { db.MachineError.Add(new MachineError() { ConnectorId = (byte)_request.connectorId, CreatedOn = _request.timestamp.HasValue ? _request.timestamp.Value : DateTime.UtcNow, Status = (int)_request.status, ChargeBoxId = session.ChargeBoxId, ErrorCodeId = (int)_request.errorCode, ErrorInfo = string.IsNullOrEmpty(_request.info) ? string.Empty : _request.info, PreStatus = _oldStatus == null ? -1 : preStatus, VendorErrorCode = string.IsNullOrEmpty(_request.vendorErrorCode) ? string.Empty : _request.vendorErrorCode, VendorId = string.IsNullOrEmpty(_request.vendorId) ? string.Empty : _request.vendorId }); } db.SaveChanges(); } if (_request.status == Packet.Messages.SubTypes.ChargePointStatus.Faulted) { var businessService = BusinessServiceFactory.CreateBusinessService(session.CustomerId.ToString()); var notification = businessService.NotifyFaultStatus(new ErrorDetails() { ChargeBoxId = session.ChargeBoxId, ConnectorId = _request.connectorId, ErrorCode = _request.errorCode, Info = string.IsNullOrEmpty(_request.info) ? string.Empty : _request.info, OCcuredOn = _request.timestamp ?? DateTime.UtcNow, VendorErrorCode = string.IsNullOrEmpty(_request.vendorErrorCode) ? string.Empty : _request.vendorErrorCode, }); } var confirm = new StatusNotificationConfirmation() { }; result.Message = confirm; result.Success = true; } break; case Actions.Heartbeat: { var confirm = new HeartbeatConfirmation() { currentTime = DateTime.UtcNow }; result.Message = confirm; result.Success = true; } break; case Actions.MeterValues: { MeterValuesRequest _request = request as MeterValuesRequest; decimal energy_kwh = 0; if (_request.meterValue.Count > 0) { using (var db = new MeterValueDBContext()) { foreach (var item in _request.meterValue) { foreach (var sampleVaule in item.sampledValue) { decimal value = Convert.ToDecimal(sampleVaule.value); if (sampleVaule.context == ReadingContext.Sample_Periodic && sampleVaule.measurand == Measurand.Energy_Active_Import_Interval) { energy_kwh = sampleVaule.unit == UnitOfMeasure.Wh ? Decimal.Divide(value, 1000) : value; } string sp = "[dbo].[uspInsertMeterValueRecord] @ChargeBoxId," + "@ConnectorId,@Value,@CreatedOn,@ContextId,@FormatId,@MeasurandId,@PhaseId,@LocationId,@UnitId,@TransactionId"; List parameter = new List { new SqlParameter("ChargeBoxId",session.ChargeBoxId), new SqlParameter("ConnectorId", (byte)_request.connectorId), new SqlParameter("Value",value), new SqlParameter("CreatedOn",item.timestamp), new SqlParameter("ContextId",sampleVaule.context.HasValue ? (int)sampleVaule.context : 0), new SqlParameter("FormatId",sampleVaule.format.HasValue ? (int)sampleVaule.format : 0), new SqlParameter("MeasurandId",sampleVaule.measurand.HasValue ? (int)sampleVaule.measurand : 0), new SqlParameter("PhaseId",sampleVaule.phase.HasValue ? (int)sampleVaule.phase : 0), new SqlParameter("LocationId",sampleVaule.location.HasValue ? (int)sampleVaule.location : 0), new SqlParameter("UnitId",sampleVaule.unit.HasValue ? (int)sampleVaule.unit : 0), new SqlParameter("TransactionId",_request.transactionId.HasValue?_request.transactionId:-1), }; db.Database.ExecuteSqlCommand(sp, parameter.ToArray()); } } } } // if (energy_kwh > 0) { try { if (session.IsBilling) if (session.IsBilling) { using (var db = new MainDBContext()) { db.ServerMessage.Add(new ServerMessage() { ChargeBoxId = session.ChargeBoxId, CreatedBy = "Server", CreatedOn = DateTime.UtcNow, OutAction = Actions.DataTransfer.ToString(), OutRequest = JsonConvert.SerializeObject( new DataTransferRequest() { messageId = "ID_TxEnergy", vendorId = "Phihong Technology", data = JsonConvert.SerializeObject(new { txId = _request.transactionId, ConnectorId = _request.connectorId }) }, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }), SerialNo = Guid.NewGuid().ToString(), InMessage = string.Empty }); db.SaveChanges(); } } } catch (Exception ex) { Console.WriteLine(string.Format("{0} :{1}", session.ChargeBoxId + " RunningCost", ex.Message)); } } var confirm = new MeterValuesConfirmation() { }; result.Message = confirm; result.Success = true; } break; case Actions.StartTransaction: { StartTransactionRequest _request = request as StartTransactionRequest; int _transactionId = -1; var businessService = BusinessServiceFactory.CreateBusinessService(session.CustomerId.ToString()); var _idTagInfo = _request.idTag == "Backend" ? new IdTagInfo() { expiryDate = DateTime.UtcNow.AddDays(1), status = AuthorizationStatus.Accepted } : await businessService.Authorize(session.ChargeBoxId, _request.idTag); //特例****飛宏客戶旗下的電樁,若遇到Portal沒回應的狀況 ~允許充電 if (session.CustomerId.ToString().ToUpper() == "8456AED9-6DD9-4BF3-A94C-9F5DCB9506F7" && _idTagInfo.status == AuthorizationStatus.ConcurrentTx) { _idTagInfo = new IdTagInfo() { expiryDate = DateTime.UtcNow.AddDays(1), status = AuthorizationStatus.Accepted }; } using (var db = new MainDBContext()) { var _CustomerId = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).Include(x => x.Customer). Select(x => x.CustomerId).FirstOrDefault(); var _existedTx = db.TransactionRecord.Where(x => x.CustomerId == _CustomerId && x.ChargeBoxId == session.ChargeBoxId && x.ConnectorId == _request.connectorId && x.StartTime == _request.timestamp).Select(C => new { C.Id }).AsNoTracking().FirstOrDefault(); TransactionRecord _newTransaction = new TransactionRecord(); if (_existedTx == null) { _newTransaction = new TransactionRecord() { ChargeBoxId = session.ChargeBoxId, ConnectorId = (byte)_request.connectorId, CreatedOn = DateTime.UtcNow, StartIdTag = _request.idTag, MeterStart = _request.meterStart, CustomerId = _CustomerId, StartTime = _request.timestamp.ToUniversalTime(), ReservationId = _request.reservationId.HasValue ? _request.reservationId.Value : 0, Fee = !session.IsBilling ? string.Empty : session.BillingMethod == 1 ? JsonConvert.SerializeObject(session.ChargingPrices) + "|" + session.Currency : session.HRPrice + "|" + session.Currency }; db.TransactionRecord.Add(_newTransaction); db.SaveChanges(); _transactionId = _newTransaction.Id; logger.Info("***************************************************** "); logger.Info(string.Format("{0} :TransactionId {1} ", session.ChargeBoxId, _newTransaction.Id)); logger.Info("***************************************************** "); } else { _transactionId = _existedTx.Id; logger.Error("Duplication ***************************************************** " + _existedTx.Id); } } var confirm = new StartTransactionConfirmation() { idTagInfo = _idTagInfo, transactionId = _transactionId }; result.Message = confirm; result.Success = true; } break; case Actions.StopTransaction: { StopTransactionRequest _request = request as StopTransactionRequest; int _ConnectorId = 0; var businessService = BusinessServiceFactory.CreateBusinessService(session.CustomerId.ToString()); //特例****飛宏客戶旗下的電樁,若遇到Portal沒回應的狀況 ~允許充電 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)); if (session.CustomerId.ToString().ToUpper() == "8456AED9-6DD9-4BF3-A94C-9F5DCB9506F7" && _idTagInfo != null && _idTagInfo.status == AuthorizationStatus.ConcurrentTx) { _idTagInfo = new IdTagInfo() { expiryDate = DateTime.UtcNow.AddDays(1), status = AuthorizationStatus.Accepted }; } using (var db = new MainDBContext()) { var transaction = db.TransactionRecord.Where(x => x.Id == _request.transactionId && x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault(); if (transaction != null) { _ConnectorId = transaction.ConnectorId; transaction.MeterStop = _request.meterStop; transaction.StopTime = _request.timestamp.ToUniversalTime(); transaction.StopReasonId = _request.reason.HasValue ? (int)_request.reason.Value : 0; transaction.StopIdTag = _request.idTag; transaction.Receipt = string.Empty; transaction.Cost = session.IsBilling ? -1 : 0; await db.SaveChangesAsync(); var confirm = new StopTransactionConfirmation() { idTagInfo = _idTagInfo }; if (session.IsBilling) { db.ServerMessage.Add(new ServerMessage() { ChargeBoxId = session.ChargeBoxId, CreatedBy = "Server", CreatedOn = DateTime.UtcNow, OutAction = Actions.DataTransfer.ToString(), OutRequest = JsonConvert.SerializeObject( new DataTransferRequest() { messageId = "ID_TxEnergy", vendorId = "Phihong Technology", data = JsonConvert.SerializeObject(new { txId = _request.transactionId, ConnectorId = transaction.ConnectorId }) }, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }), SerialNo = Guid.NewGuid().ToString(), InMessage = string.Empty }); db.SaveChanges(); } result.Message = confirm; result.Success = true; } else { result.Exception = new Exception("Can't find transactionId " + _request.transactionId); } } if (_request.transactionData != null) { if (_request.transactionData.Count > 0) { using (var _meterDb = new MeterValueDBContext()) { foreach (var item in _request.transactionData) { foreach (var sampleVaule in item.sampledValue) { decimal value = Convert.ToDecimal(sampleVaule.value); string sp = "[dbo].[uspInsertMeterValueRecord] @ChargeBoxId," + "@ConnectorId,@Value,@CreatedOn,@ContextId,@FormatId,@MeasurandId,@PhaseId,@LocationId,@UnitId,@TransactionId"; List parameter = new List { new SqlParameter("ChargeBoxId",session.ChargeBoxId), new SqlParameter("ConnectorId", (byte)_ConnectorId), new SqlParameter("Value",value), new SqlParameter("CreatedOn",item.timestamp), new SqlParameter("ContextId",sampleVaule.context.HasValue ? (int)sampleVaule.context : 0), new SqlParameter("FormatId",sampleVaule.format.HasValue ? (int)sampleVaule.format : 0), new SqlParameter("MeasurandId",sampleVaule.measurand.HasValue ? (int)sampleVaule.measurand : 0), new SqlParameter("PhaseId",sampleVaule.phase.HasValue ? (int)sampleVaule.phase : 0), new SqlParameter("LocationId",sampleVaule.location.HasValue ? (int)sampleVaule.location : 0), new SqlParameter("UnitId",sampleVaule.unit.HasValue ? (int)sampleVaule.unit : 0), new SqlParameter("TransactionId",_request.transactionId), }; _meterDb.Database.ExecuteSqlCommand(sp, parameter.ToArray()); } } } } } } break; case Actions.Authorize: { AuthorizeRequest _request = request as AuthorizeRequest; //特例****飛宏客戶旗下的電樁,若遇到Portal沒回應的狀況 ~允許充電 var businessService = BusinessServiceFactory.CreateBusinessService(session.CustomerId.ToString()); var confirm = new AuthorizeConfirmation() { idTagInfo = _request.idTag == "Backend" ? new IdTagInfo() { expiryDate = DateTime.UtcNow.AddDays(1), status = AuthorizationStatus.Accepted } : await businessService.Authorize(session.ChargeBoxId, _request.idTag) }; if (session.CustomerId.ToString().ToUpper() == "8456AED9-6DD9-4BF3-A94C-9F5DCB9506F7" && confirm.idTagInfo.status == AuthorizationStatus.ConcurrentTx) { confirm.idTagInfo = new IdTagInfo() { expiryDate = DateTime.UtcNow.AddDays(1), status = AuthorizationStatus.Accepted }; } result.Message = confirm; result.Success = true; } break; default: { Console.WriteLine(string.Format("Not Implement {0} Logic(ExecuteCoreRequest)", request.GetType().ToString().Replace("OCPPPackage.Messages.Core.", ""))); } break; } } catch (Exception ex) { logger.Fatal(string.Format("chargeBoxId:{0} {1}", session.ChargeBoxId, action)); logger.Fatal(string.Format("Data {0}", request.ToString())); logger.Fatal(string.Format("Error {0}", ex.ToString())); result.Exception = ex; } if (action == Actions.Heartbeat) { watch.Stop(); if (watch.ElapsedMilliseconds / 1000 > 3) { logger.Error("Processing Hearbeat costs " + watch.ElapsedMilliseconds / 1000 + " seconds"); } } return result; } internal MessageResult ExecuteCoreConfirm(Actions action, ClientData session, IConfirmation confirm, string requestId) { MessageResult result = new MessageResult() { Success = true }; try { switch (action) { case Actions.DataTransfer: { DataTransferConfirmation _confirm = confirm as DataTransferConfirmation; DataTransferRequest _request = _confirm.GetRequest() as DataTransferRequest; using (var db = new MainDBContext()) { var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId && x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault(); if (operation != null) { operation.FinishedOn = DateTime.UtcNow; operation.Status = 1;//電樁有回覆 operation.EVSE_Status = (int)_confirm.status; operation.EVSE_Value = string.IsNullOrEmpty(_confirm.data) ? "" : _confirm.data; db.SaveChanges(); } if (_request.messageId == "ID_FirmwareVersion") { var machine = new Machine() { Id = session.MachineId }; if (machine != null) { db.Configuration.AutoDetectChangesEnabled = false; db.Configuration.ValidateOnSaveEnabled = false; db.Machine.Attach(machine); machine.BoardVersions = _confirm.data; db.Entry(machine).Property(x => x.BoardVersions).IsModified = true; db.SaveChanges(); } } if (_request.messageId == "ID_TxEnergy") { if (_confirm.status == DataTransferStatus.Accepted) { string receipt = string.Empty; List bill = new List(); List chargingPrices = new List(); var txEnergy = JsonConvert.DeserializeObject(_confirm.data); var feedto = db.TransactionRecord.Where(x => x.Id == txEnergy.TxId).Select(x => new { Fee = x.Fee, StopTime = x.StopTime, StartTime = x.StartTime }).FirstOrDefault(); if (feedto == null || string.IsNullOrEmpty(feedto.Fee)) return result; string currency = feedto.Fee.Substring(feedto.Fee.Length - 3); decimal sum = 0; if (feedto.Fee.Length > 10) { chargingPrices = JsonConvert.DeserializeObject>(feedto.Fee.Split('|')[0]); foreach (var item in txEnergy.PeriodEnergy) { var periodEnergy = Math.Round(item.Value, 2, MidpointRounding.AwayFromZero); string startTime = item.Key.Length == 1 ? "0" + item.Key + ":00" : item.Key + ":00"; decimal perfee = 0; if (chargingPrices.Count == 1) { perfee = Decimal.Multiply(periodEnergy, chargingPrices[0].Fee); if (bill.Count == 0) { bill.Add(new ChargingBill() { StartTime = "00:00", EndTime = "23:59", Fee = chargingPrices[0].Fee }); } bill[0].PeriodEnergy += periodEnergy; } else { var price = chargingPrices.Where(x => x.StartTime == startTime).FirstOrDefault(); perfee = Decimal.Multiply(periodEnergy, price.Fee); bill.Add(new ChargingBill() { StartTime = price.StartTime, EndTime = price.EndTime, PeriodEnergy = periodEnergy, Fee = chargingPrices[0].Fee }); } if (bill.Count > 0) { bill[bill.Count - 1].Total += DollarRounding(perfee, session.Currency); sum += bill[bill.Count - 1].Total; if (bill.Count == 1) { sum = bill[bill.Count - 1].Total; } } } } else { // 以時計費 var fee = decimal.Parse(feedto.Fee.Split('|')[0]); var totalHours = Math.Round(DateTime.UtcNow.Subtract(feedto.StartTime).TotalHours, 2, MidpointRounding.AwayFromZero); sum = Decimal.Multiply((decimal)totalHours, fee); sum = DollarRounding(sum, session.Currency); receipt = totalHours + "hrs @ $" + fee + "/hr =" + sum; } if (feedto.StopTime != GlobalConfig.DefaultNullTime) { var tx = db.TransactionRecord.Where(x => x.Id == txEnergy.TxId).FirstOrDefault(); if (tx == null) { Console.WriteLine("Tx is empty"); return result; } var startTime = new DateTime(tx.StartTime.Year, tx.StartTime.Month, tx.StartTime.Day, tx.StartTime.Hour, 0, 0); List confirmbill = new List(); while (startTime < tx.StopTime) { if (bill.Count == 1) { confirmbill = bill; receipt = string.Format("{0} kWh @ ${1}/kWh={2}", bill[0].PeriodEnergy, bill[0].Fee, bill[0].Total); break; } if (bill.Count > 1) { confirmbill.Add(bill.Where(x => x.StartTime == startTime.ToString("HH:00")).FirstOrDefault()); if (confirmbill.Count == 24) break; if (confirmbill.Count > 1) { receipt += "|"; } receipt += string.Format("{0}~{1} {2} kWh @ ${3}/kWh={4}", confirmbill[confirmbill.Count - 1].StartTime, confirmbill[confirmbill.Count - 1].EndTime, confirmbill[confirmbill.Count - 1].PeriodEnergy, bill[0].Fee, confirmbill[confirmbill.Count - 1].Total); } startTime = startTime.AddHours(1); } if (bill.Count > 0) { confirmbill = confirmbill.Where(x => string.IsNullOrEmpty(x.StartTime) == false).ToList(); } tx.Cost = sum; tx.Receipt = receipt; db.Configuration.AutoDetectChangesEnabled = false; db.Configuration.ValidateOnSaveEnabled = false; db.TransactionRecord.Attach(tx); db.Entry(tx).Property(x => x.Cost).IsModified = true; db.Entry(tx).Property(x => x.Receipt).IsModified = true; db.ServerMessage.Add(new ServerMessage() { ChargeBoxId = session.ChargeBoxId, CreatedBy = "Server", CreatedOn = DateTime.UtcNow, OutAction = Actions.DataTransfer.ToString(), OutRequest = JsonConvert.SerializeObject( new DataTransferRequest() { messageId = "FinalCost", vendorId = "Phihong Technology", data = JsonConvert.SerializeObject(new { txId = txEnergy.TxId, description = string.Format("Connection Fee: $0.00 {0}; Session Fee: ${1} {0}; Occupancy Fee: " + "$0.00 {0}; Total Cost: ${1} {0}; Account Balance: $10.00 {0}", currency, sum) }) }, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }), SerialNo = Guid.NewGuid().ToString(), InMessage = string.Empty }); ; db.SaveChanges(); } else { db.ServerMessage.Add(new ServerMessage() { ChargeBoxId = session.ChargeBoxId, CreatedBy = "Server", CreatedOn = DateTime.UtcNow, OutAction = Actions.DataTransfer.ToString(), OutRequest = JsonConvert.SerializeObject( new DataTransferRequest() { messageId = "RunningCost", vendorId = "Phihong Technology", data = JsonConvert.SerializeObject(new { txId = txEnergy.TxId, description = string.Format("Connection Fee: $0.00 {0}; Session Fee: ${1} {0}; Occupancy Fee: " + "$0.00 {0}; Total Cost: ${1} {0}; Account Balance: $0.00 {0}", currency, sum) }) }, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }), SerialNo = Guid.NewGuid().ToString(), InMessage = string.Empty }); ; db.SaveChanges(); } } } } } break; case Actions.ChangeAvailability: { ChangeAvailabilityConfirmation _confirm = confirm as ChangeAvailabilityConfirmation; ChangeAvailabilityRequest _request = _confirm.GetRequest() as ChangeAvailabilityRequest; using (var db = new MainDBContext()) { var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId && x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault(); if (operation != null) { operation.FinishedOn = DateTime.UtcNow; operation.Status = 1;//電樁有回覆 operation.EVSE_Status = (int)_confirm.status; operation.EVSE_Value = _confirm.status.ToString(); db.SaveChanges(); } } } break; case Actions.ClearCache: { ClearCacheConfirmation _confirm = confirm as ClearCacheConfirmation; ClearCacheRequest _request = _confirm.GetRequest() as ClearCacheRequest; using (var db = new MainDBContext()) { var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId && x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault(); if (operation != null) { operation.FinishedOn = DateTime.UtcNow; operation.Status = 1;//電樁有回覆 operation.EVSE_Status = (int)_confirm.status; operation.EVSE_Value = _confirm.status.ToString(); db.SaveChanges(); } } } break; case Actions.RemoteStartTransaction: { RemoteStartTransactionConfirmation _confirm = confirm as RemoteStartTransactionConfirmation; RemoteStartTransactionRequest _request = _confirm.GetRequest() as RemoteStartTransactionRequest; using (var db = new MainDBContext()) { var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId && x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault(); if (operation != null) { operation.FinishedOn = DateTime.UtcNow; operation.Status = 1;//電樁有回覆 operation.EVSE_Status = (int)_confirm.status; operation.EVSE_Value = _confirm.status.ToString(); db.SaveChanges(); } } } break; case Actions.RemoteStopTransaction: { RemoteStopTransactionConfirmation _confirm = confirm as RemoteStopTransactionConfirmation; RemoteStopTransactionRequest _request = _confirm.GetRequest() as RemoteStopTransactionRequest; using (var db = new MainDBContext()) { var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId && x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault(); if (operation != null) { operation.FinishedOn = DateTime.UtcNow; operation.Status = 1;//電樁有回覆 operation.EVSE_Status = (int)_confirm.status; operation.EVSE_Value = _confirm.status.ToString(); db.SaveChanges(); } } } break; case Actions.Reset: { ResetConfirmation _confirm = confirm as ResetConfirmation; ResetRequest _request = _confirm.GetRequest() as ResetRequest; using (var db = new MainDBContext()) { var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId && x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault(); if (operation != null) { operation.FinishedOn = DateTime.UtcNow; operation.Status = 1;//電樁有回覆 operation.EVSE_Status = (int)_confirm.status; operation.EVSE_Value = _confirm.status.ToString(); db.SaveChanges(); } } } break; case Actions.ChangeConfiguration: { ChangeConfigurationConfirmation _confirm = confirm as ChangeConfigurationConfirmation; ChangeConfigurationRequest _request = _confirm.GetRequest() as ChangeConfigurationRequest; using (var db = new MainDBContext()) { var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId && x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault(); if (operation != null) { operation.FinishedOn = DateTime.UtcNow; operation.Status = 1;//電樁有回覆 operation.EVSE_Status = (int)_confirm.status; operation.EVSE_Value = _confirm.status.ToString(); } if (_confirm.status == Packet.Messages.SubTypes.ConfigurationStatus.Accepted || _confirm.status == Packet.Messages.SubTypes.ConfigurationStatus.RebootRequired) { var configure = db.MachineConfiguration.Where(x => x.ChargeBoxId == session.ChargeBoxId).ToList(); var foundConfig = configure.Find(x => x.ConfigureName == _request.key); if (foundConfig != null) { foundConfig.ReadOnly = false; foundConfig.ConfigureSetting = _request.value; } else { db.MachineConfiguration.Add(new MachineConfiguration() { ChargeBoxId = session.ChargeBoxId, ConfigureName = _request.key, ReadOnly = false, ConfigureSetting = _request.value }); } } db.SaveChanges(); } } break; case Actions.GetConfiguration: { try { GetConfigurationConfirmation _confirm = confirm as GetConfigurationConfirmation; // GetConfigurationRequest _request = _confirm.GetRequest() as GetConfigurationRequest; using (var db = new MainDBContext()) { var configure = db.MachineConfiguration.Where(x => x.ChargeBoxId == session.ChargeBoxId).ToList(); if (_confirm.configurationKey != null) { foreach (var item in _confirm.configurationKey) { string oldValue = string.Empty; if (item.key == null) { Console.WriteLine("*********************"); } var foundConfig = configure.Find(x => x.ConfigureName == item.key); if (foundConfig != null) { if (foundConfig.ConfigureName == null) { Console.WriteLine("*********************"); } if (foundConfig.ConfigureName == "SecurityProfile") { oldValue = foundConfig.ConfigureSetting; } foundConfig.ReadOnly = item.IsReadOnly; foundConfig.ConfigureSetting = string.IsNullOrEmpty(item.value) ? string.Empty : item.value; } else { db.MachineConfiguration.Add(new MachineConfiguration() { ChargeBoxId = session.ChargeBoxId, ConfigureName = item.key, ReadOnly = item.IsReadOnly, ConfigureSetting = string.IsNullOrEmpty(item.value) ? string.Empty : item.value, Exists = true }); } } } if (_confirm.unknownKey != null) { foreach (var item in _confirm.unknownKey) { var foundConfig = configure.Find(x => x.ConfigureName == item); if (foundConfig != null) { foundConfig.ReadOnly = true; foundConfig.ConfigureSetting = string.Empty; foundConfig.Exists = false; } else { db.MachineConfiguration.Add(new MachineConfiguration() { ChargeBoxId = session.ChargeBoxId, ConfigureName = item }); } } } var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId && x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault(); if (operation != null) { operation.FinishedOn = DateTime.UtcNow; operation.Status = 1;//電樁有回覆 operation.EVSE_Status = 1; operation.EVSE_Value = JsonConvert.SerializeObject(_confirm.configurationKey, Formatting.None); } db.SaveChanges(); } } catch (Exception ex) { logger.Error(ex.ToString()); } } break; case Actions.UnlockConnector: { UnlockConnectorConfirmation _confirm = confirm as UnlockConnectorConfirmation; UnlockConnectorRequest _request = _confirm.GetRequest() as UnlockConnectorRequest; using (var db = new MainDBContext()) { var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId && x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault(); if (operation != null) { operation.FinishedOn = DateTime.UtcNow; operation.Status = 1;//電樁有回覆 operation.EVSE_Status = (int)_confirm.status; operation.EVSE_Value = _confirm.status.ToString(); db.SaveChanges(); } } } break; default: { Console.WriteLine(string.Format("Not Implement {0} Logic(ExecuteCoreConfirm)", confirm.GetType().ToString().Replace("OCPPPackage.Messages.Core.", ""))); } break; } } catch (Exception ex) { logger.Debug("123 " + ex.ToString()); } return result; } internal MessageResult ReceivedCoreError(Actions action, string errorMsg, ClientData session, string requestId) { MessageResult result = new MessageResult() { Success = true }; switch (action) { case Actions.ChangeAvailability: case Actions.ChangeConfiguration: case Actions.ClearCache: case Actions.RemoteStartTransaction: case Actions.RemoteStopTransaction: case Actions.Reset: case Actions.GetConfiguration: case Actions.UnlockConnector: case Actions.DataTransfer: { if (action == Actions.DataTransfer) { logger.Debug(string.Format("DataTransfer Error {0}: {1}", session.ChargeBoxId, requestId)); } using (var db = new MainDBContext()) { var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId && x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault(); if (operation != null) { operation.FinishedOn = DateTime.UtcNow; operation.Status = 1;//電樁有回覆 operation.EVSE_Status = (int)255;//錯誤 operation.EVSE_Value = errorMsg; db.SaveChanges(); } } } break; default: { Console.WriteLine(string.Format("Not Implement {0} Logic(ReceivedCoreError)", action)); } break; } return result; } /// /// 依據幣值處理4捨5入 /// /// /// /// private decimal DollarRounding(decimal money, string currency) { if (currency == "USD" || currency == "EUR") { //0.4867 if ((double)((int)(money * 100) + 0.5) <= (double)(money * 100)) { //money = Decimal.Add(money, (decimal)0.01);//0.4967 } money = Math.Round(money, 2, MidpointRounding.AwayFromZero); money = Decimal.Parse(money.ToString("0.00")); } else { if ((double)((int)(money) + 0.5) <= (double)money) { // money = (int) money + 1; } money = Math.Round(money, 0, MidpointRounding.AwayFromZero); money = Decimal.Parse(money.ToString("0")); } return money; } } }