using Dapper; 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 Newtonsoft.Json.Linq; using NLog; using OCPPPackage.Profiles; using OCPPServer.Protocol; using System; using System.Collections; using System.Collections.Generic; using System.Configuration; using System.Data; using System.Data.Entity; using System.Data.SqlClient; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Threading.Tasks; namespace EVCB_OCPP.WSServer.Message { public class ID_CreditDeductResult { public int txId { set; get; } public string creditNo { set; get; } public bool deductResult { set; get; } public bool isDonateInvoice { set; get; } public decimal amount { set; get; } public string approvalNo { set; get; } } public class ID_ReaderStatus { public int ConnectorId { set; get; } public string creditNo { set; get; } public string SerialNo { set; get; } public int readerStatus { set; get; } public string VEMData { set; get; } public DateTime Timestamp { set; get; } } internal partial class ProfileHandler { static private ILogger logger = NLog.LogManager.GetCurrentClassLogger(); string webConnectionString = ConfigurationManager.ConnectionStrings["WebDBContext"].ConnectionString; private OuterHttpClient httpClient = new OuterHttpClient(); 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: { DataTransferRequest _request = request as DataTransferRequest; var confirm = new DataTransferConfirmation() { status = DataTransferStatus.UnknownMessageId }; if (_request.messageId == "ID_CreditDeductResult") { var creditDeductResult = JsonConvert.DeserializeObject(_request.data); if (session.CustomerId == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8")) { var report = new { ChargeBoxId = session.ChargeBoxId, IsDonateInvoice = creditDeductResult.isDonateInvoice, CreditNo = creditDeductResult.creditNo, DeductResult = creditDeductResult.deductResult, SessionId = creditDeductResult.txId, ApprovalNo = creditDeductResult.approvalNo, TotalCost = creditDeductResult.amount, }; var response = await httpClient.Post(GlobalConfig.TCC_API_URL + "prepare_issue_invoice", new Dictionary() { { "PartnerId",session.CustomerId.ToString()} }, report, GlobalConfig.TCC_SALTKEY); logger.Debug(JsonConvert.SerializeObject(response)); } confirm.status = DataTransferStatus.Accepted; confirm.data = JsonConvert.SerializeObject(new { txId = creditDeductResult.txId, creditNo = creditDeductResult.creditNo, msgId = _request.messageId }); } if (_request.messageId == "ID_ReaderStatus") { if (session.CustomerId == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8")) { var preauth_status = JsonConvert.DeserializeObject(_request.data); var report = new { ChargeBoxId = session.ChargeBoxId, ConnectorId = preauth_status.ConnectorId, CreditNo = preauth_status.creditNo, ReaderStatus = preauth_status.readerStatus, SerialNo = preauth_status.SerialNo, VEMData = preauth_status.VEMData, Timestamp = preauth_status.Timestamp }; var response = await httpClient.Post(GlobalConfig.TCC_API_URL + "preauth_status", new Dictionary() { { "PartnerId",session.CustomerId.ToString()} }, report, GlobalConfig.TCC_SALTKEY); confirm.status = DataTransferStatus.Accepted; } } if (_request.messageId == "ID_OCMF") { JObject jo = JObject.Parse(_request.data); logger.Debug(string.Format("{0}\r\n{1}\r\n{2}", jo["txId"].Value(), jo["dataString"].Value(), jo["publicKey"].Value())); using (var db = new MainDBContext()) { db.OCMF.Add(new OCMF() { TransactionId = jo["txId"].Value(), DataString = jo["dataString"].Value(), PublicKey = jo["publicKey"].Value() }); await db.SaveChangesAsync(); } confirm.status = DataTransferStatus.Accepted; confirm.data = JsonConvert.SerializeObject(new { txId = jo["txId"].Value(), msgId = _request.messageId }); } if (_request.messageId == "Authorize") { string iso15118_token = string.Empty; JObject jo = JObject.Parse(_request.data); if (jo.ContainsKey("idToken")) { iso15118_token = jo["idToken"]["idToken"].Value(); } confirm.status = DataTransferStatus.Accepted; confirm.data = JsonConvert.SerializeObject(new { certificateStatus = iso15118_token == "12345678901234" ? "Accepted" : "CertificateExpired", idTokenInfo = new { status = iso15118_token == "12345678901234" ? "Accepted" : "Invalid" } }); } 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); } } if (session.IsPending == true) { session.IsPending = false; } if (session.IsPending == null) { session.IsPending = true; } var confirm = new BootNotificationConfirmation() { currentTime = DateTime.UtcNow, interval = session.IsPending.Value ? 5 : heartbeat_interval, status = session.IsPending.Value ? RegistrationStatus.Pending : RegistrationStatus.Accepted }; 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; if (_request.meterValue.Count > 0) { using (var db = new MeterValueDBContext()) { foreach (var item in _request.meterValue) { if (_request.transactionId.HasValue) { decimal meterStart = 0; var energy_Register = item.sampledValue.Where(x => x.measurand == Measurand.Energy_Active_Import_Register).FirstOrDefault(); if (energy_Register != null) { decimal energyRegister = decimal.Parse(energy_Register.value); energyRegister = energy_Register.unit.Value == UnitOfMeasure.kWh ? decimal.Multiply(energyRegister, 1000) : energyRegister; using (var maindb = new MainDBContext()) { meterStart = maindb.TransactionRecord.Where(x => x.Id == _request.transactionId.Value).Select(x => x.MeterStart).FirstOrDefault(); } item.sampledValue.Add(new SampledValue() { context = ReadingContext.Sample_Periodic, format = ValueFormat.Raw, location = Location.Outlet, phase = item.sampledValue.Where(x => x.measurand == Measurand.Energy_Active_Import_Register).Select(x => x.phase).FirstOrDefault(), unit = UnitOfMeasure.Wh, measurand = Measurand.TotalEnergy, value = decimal.Subtract(energyRegister, meterStart).ToString() }); } } 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)_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) { 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 = new IdTagInfo() { expiryDate = DateTime.UtcNow.AddDays(1), status = AuthorizationStatus.Accepted }; #region PnC 邏輯 if (!string.IsNullOrEmpty(_request.idTag)) { _request.idTag = _request.idTag.StartsWith("vid:") ? _request.idTag.Replace("vid:", "") : _request.idTag; } #endregion if (_request.idTag != "Backend") { var authorization_result = await businessService.Authorize(session.ChargeBoxId, _request.idTag); _idTagInfo = authorization_result.IdTagInfo; if (_idTagInfo.status == AuthorizationStatus.Accepted && authorization_result.ChargePointFee != null) { var price = authorization_result.ChargePointFee.Where(x => x.IsAC == session.IsAC).First(); if (price != null) { if (session.UserPrices.ContainsKey(_request.idTag)) { session.UserPrices[_request.idTag] = price.PerkWhFee.HasValue ? JsonConvert.SerializeObject(new List() { new ChargingPrice() { StartTime = "00:00", EndTime = "23:59", Fee = price.PerkWhFee.Value } }) : price.PerHourFee.Value.ToString(); session.UserPrices[_request.idTag] += "|+" + authorization_result.AccountBalance + "+" + "&" + price.ParkingFee + "&|" + price.Currency; } else { session.UserPrices.Add(_request.idTag, price.PerkWhFee.HasValue ? JsonConvert.SerializeObject(new List() { new ChargingPrice() { StartTime = "00:00", EndTime = "23:59", Fee = price.PerkWhFee.Value } }) : price.PerHourFee.Value.ToString()); session.UserPrices[_request.idTag] += "|+" + authorization_result.AccountBalance + "+" + "&" + price.ParkingFee + "&|" + price.Currency; } } } } //特例****飛宏客戶旗下的電樁,若遇到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 }; } string accountBalance = "0"; if (session.CustomerId.ToString().ToUpper() == "10C7F5BD-C89A-4E2A-8611-B617E0B41A73") { using (SqlConnection conn = new SqlConnection(webConnectionString)) { var parameters = new DynamicParameters(); parameters.Add("@IdTag", _request.idTag, DbType.String, ParameterDirection.Input); string strSql = "select parentIdTag from [dbo].[LocalListDetail] where ListId = 27 and IdTag=@IdTag; "; accountBalance = conn.ExecuteScalar(strSql, parameters); } } 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, }; if (session.UserPrices.ContainsKey(_request.idTag)) { _newTransaction.Fee = !session.IsBilling ? string.Empty : session.UserPrices[_request.idTag]; } else { _newTransaction.Fee = !session.IsBilling ? string.Empty : session.BillingMethod == 1 ? JsonConvert.SerializeObject(session.ChargingPrices) : session.ChargingFeebyHour.ToString(); _newTransaction.Fee += !session.IsBilling ? string.Empty : "|+" + accountBalance + "+" + "&" + session.ParkingFee + "&|" + 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 stopRequest = request as StopTransactionRequest; IdTagInfo idTagInfo = null; int connectorId = 0; //特例****飛宏客戶旗下的電樁,若遇到Portal沒回應的狀況 ~允許充電 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 }; } try { using (var db = new MainDBContext()) { var transaction = db.TransactionRecord.Where(x => x.Id == stopRequest.transactionId && x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault(); var businessService = BusinessServiceFactory.CreateBusinessService(session.CustomerId.ToString()); idTagInfo = string.IsNullOrEmpty(stopRequest.idTag) ? null : (stopRequest.idTag == "Backend" ? new IdTagInfo() { expiryDate = DateTime.UtcNow.AddDays(1), status = AuthorizationStatus.Accepted } : (await businessService.Authorize(session.ChargeBoxId, stopRequest.idTag, transaction.ConnectorId)).IdTagInfo); #region PnC 邏輯 if (!string.IsNullOrEmpty(stopRequest.idTag)) { stopRequest.idTag = stopRequest.idTag.StartsWith("vid:") ? stopRequest.idTag.Replace("vid:", "") : stopRequest.idTag; } #endregion #region 加入Transaction Start/StopSOC if (!session.IsAC && stopRequest.transactionId > 0) { var SearchTime = transaction.StartTime; var txStopTime = stopRequest.timestamp; List SOCCollection = new List(); while (SearchTime.Date <= txStopTime.Date) { var searchResults = await GetTransactionSOC(transaction.Id, SearchTime.Date); SOCCollection.AddRange(searchResults); SearchTime = SearchTime.AddDays(1); } SOCCollection.Sort(); logger.Debug(string.Format("SOCCollection:" + String.Join(",", SOCCollection.Select(x => x.ToString()).ToArray()))); transaction.StartSOC = SOCCollection.Count() == 0 ? "" : SOCCollection.First().ToString("0"); transaction.StopSOC = SOCCollection.Count() == 0 ? "" : SOCCollection.Last().ToString("0"); } #endregion //遠傳太久以前的停止充電 直接拒絕 避免電樁持續重送~~~~~~~ if (stopRequest.timestamp < new DateTime(2021, 11, 1)) { var confirm = new StopTransactionConfirmation() { idTagInfo = new IdTagInfo() { status = AuthorizationStatus.Invalid } }; result.Message = confirm; result.Success = true; return result; } if (transaction != null) { var confirm = new StopTransactionConfirmation() { idTagInfo = idTagInfo }; //Avoid rewrite transaction data if (transaction.StopTime != GlobalConfig.DefaultNullTime) { result.Message = confirm; result.Success = true; return result; } connectorId = transaction.ConnectorId; transaction.MeterStop = stopRequest.meterStop; transaction.StopTime = stopRequest.timestamp.ToUniversalTime(); transaction.StopReasonId = stopRequest.reason.HasValue ? (int)stopRequest.reason.Value : 0; transaction.StopReason = stopRequest.reason.HasValue ? stopRequest.reason.Value.ToString() : Reason.Local.ToString(); transaction.StopIdTag = stopRequest.idTag; transaction.Receipt = string.Empty; transaction.Cost = session.IsBilling ? -1 : 0; if (stopRequest.transactionData == null || stopRequest.transactionData.Count == 0) { stopRequest.transactionData = new List() { new MeterValue() { timestamp= stopRequest.timestamp, sampledValue=new List()} }; } if (stopRequest.transactionData != null && stopRequest.transactionData.Count >= 0) { //清除 StopTransaction TransactionData stopRequest.transactionData[0].sampledValue.Clear(); stopRequest.transactionData[0].sampledValue.Add(new SampledValue() { context = ReadingContext.Transaction_End, format = ValueFormat.Raw, location = Location.Outlet, phase = stopRequest.transactionData[0].sampledValue.Where(x => x.context.HasValue).Select(x => x.phase).FirstOrDefault(), unit = UnitOfMeasure.Wh, measurand = Measurand.TotalEnergy, value = decimal.Subtract(transaction.MeterStop, transaction.MeterStart).ToString() }); } await db.SaveChangesAsync(); 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 = stopRequest.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 " + stopRequest.transactionId); } } #region Save MeterValue if (stopRequest.transactionData != null) { if (stopRequest.transactionData.Count > 0) { using (var _meterDb = new MeterValueDBContext()) { foreach (var item in stopRequest.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",stopRequest.transactionId), }; _meterDb.Database.ExecuteSqlCommand(sp, parameter.ToArray()); } } } } } #endregion } catch (Exception ex) { result.Exception = new Exception("TransactionId " + stopRequest.transactionId + " " + ex.Message); result.CallErrorMsg = "Reject Response Message"; result.Success = false; // return result; } } break; case Actions.Authorize: { AuthorizeRequest _request = request as AuthorizeRequest; var businessService = BusinessServiceFactory.CreateBusinessService(session.CustomerId.ToString()); var confirm = new AuthorizeConfirmation() { idTagInfo = new IdTagInfo() { expiryDate = DateTime.UtcNow.AddDays(1), status = AuthorizationStatus.Accepted } }; if (_request.idTag != "Backend") { var authorization_result = await businessService.Authorize(session.ChargeBoxId, _request.idTag); confirm.idTagInfo = authorization_result.IdTagInfo; if (confirm.idTagInfo.status == AuthorizationStatus.Accepted && authorization_result.ChargePointFee != null) { var price = authorization_result.ChargePointFee.Where(x => x.IsAC == session.IsAC).First(); if (price != null) { if (session.UserPrices.ContainsKey(_request.idTag)) { session.UserPrices[_request.idTag] = price.PerkWhFee.HasValue ? JsonConvert.SerializeObject(new List() { new ChargingPrice() { StartTime = "00:00", EndTime = "23:59", Fee = price.PerkWhFee.Value } }) : price.PerHourFee.Value.ToString(); session.UserPrices[_request.idTag] += "|+" + authorization_result.AccountBalance + "+" + "&" + price.ParkingFee + "&|" + price.Currency; } else { session.UserPrices.Add(_request.idTag, price.PerkWhFee.HasValue ? JsonConvert.SerializeObject(new List() { new ChargingPrice() { StartTime = "00:00", EndTime = "23:59", Fee = price.PerkWhFee.Value } }) : price.PerHourFee.Value.ToString()); session.UserPrices[_request.idTag] += "|+" + authorization_result.AccountBalance + "+" + "&" + price.ParkingFee + "&|" + price.Currency; } if (session.UserDisplayPrices.ContainsKey(_request.idTag)) { session.UserDisplayPrices[_request.idTag] = price.DisplayMessage; } else { session.UserDisplayPrices.Add(_request.idTag, price.DisplayMessage); } } } } //特例****飛宏客戶旗下的電樁,若遇到Portal沒回應的狀況 ~允許充電 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; } async internal Task 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; await db.SaveChangesAsync(); } 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; await db.SaveChangesAsync(); } } if (_request.messageId == "ID_TxEnergy") //計費 { if (_confirm.status == DataTransferStatus.Accepted) { decimal couponPoint = 0m; string farewellMessage = string.Empty; 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 { Id = x.Id, ConnectorId = x.ConnectorId, Fee = x.Fee, StopTime = x.StopTime, StartTime = x.StartTime }).FirstOrDefault(); decimal chargedEnergy = 0m; if (feedto == null || string.IsNullOrEmpty(feedto.Fee)) return result; string currency = feedto.Fee.Substring(feedto.Fee.Length - 3); decimal chargingCost = 0; if (feedto.Fee.Length > 58) { chargingPrices = JsonConvert.DeserializeObject>(feedto.Fee.Split('|')[0]); foreach (var item in txEnergy.PeriodEnergy) { DateTime dt = new DateTime(2021, 01, 01, int.Parse(item.Key), 0, 0, DateTimeKind.Utc); string startTime = dt.ToString("hh:mm tt", new CultureInfo("en-us")); decimal perfee = 0; //小數點無條件捨去到第4位 var periodEnergy = (decimal)((int)Decimal.Multiply(item.Value, 10000) / (double)10000); chargedEnergy += periodEnergy; if (chargingPrices.Count == 1) { perfee = Decimal.Multiply(periodEnergy, chargingPrices[0].Fee); if (bill.Count == 0) { bill.Add(new ChargingBill() { StartTime = "12:00 AM", EndTime = "11:59 PM", 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 = price.Fee, }); } if (bill.Count > 0) { bill[bill.Count - 1].Total += DollarRounding(perfee, session.Currency); chargingCost += bill[bill.Count - 1].Total; if (bill.Count == 1) { bill[bill.Count - 1].Total = DollarRounding(Decimal.Multiply(bill[0].PeriodEnergy, bill[0].Fee), session.Currency); chargingCost = bill[bill.Count - 1].Total; } } } } else { //以小時計費 foreach (var item in txEnergy.PeriodEnergy) { //小數點無條件捨去到第4位 var periodEnergy = (decimal)((int)Decimal.Multiply(item.Value, 10000) / (double)10000); chargedEnergy += periodEnergy; } var fee = decimal.Parse(feedto.Fee.Split('|')[0]); var charging_stoptime = feedto.StopTime == GlobalConfig.DefaultNullTime ? DateTime.Parse(DateTime.UtcNow.ToString("yyyy/MM/dd HH:mm")) : DateTime.Parse(feedto.StopTime.ToString("yyyy/MM/dd HH:mm")); var charging_starttime = DateTime.Parse(feedto.StartTime.ToString("yyyy/MM/dd HH:mm")); chargingCost = Decimal.Multiply((decimal)charging_stoptime.Subtract(charging_starttime).TotalHours, fee); chargingCost = DollarRounding(chargingCost, session.Currency); } // 計算停車費 var parkingFee = decimal.Parse(feedto.Fee.Split('&')[1]); var stoptime = feedto.StopTime == GlobalConfig.DefaultNullTime ? DateTime.Parse(DateTime.UtcNow.ToString("yyyy/MM/dd HH:mm")) : DateTime.Parse(feedto.StopTime.ToString("yyyy/MM/dd HH:mm")); var starttime = DateTime.Parse(feedto.StartTime.ToString("yyyy/MM/dd HH:mm")); var totalHours = stoptime.Subtract(starttime).TotalHours; var parkingCost = Decimal.Multiply((decimal)totalHours, parkingFee); parkingCost = DollarRounding(parkingCost, session.Currency); if (feedto.StopTime != GlobalConfig.DefaultNullTime) { var customerInfo = db.Customer.Where(x => x.Id == session.CustomerId).Select(x => new { x.InstantStopTxReport, x.ApiUrl, x.ApiKey }).FirstOrDefault(); decimal accountBalance = 0; decimal.TryParse(feedto.Fee.Split('+')[1], out accountBalance); var tx = db.TransactionRecord.Where(x => x.Id == txEnergy.TxId).FirstOrDefault(); if (tx == null) { Console.WriteLine("Tx is empty"); return result; } if (tx.BillingDone) return result; var startTime = new DateTime(tx.StartTime.Year, tx.StartTime.Month, tx.StartTime.Day, tx.StartTime.Hour, 0, 0); List confirmbill = new List(); receipt = string.Format("({0} )Energy:", chargedEnergy); while (startTime < tx.StopTime) { if (bill.Count == 1) { confirmbill = bill; receipt += string.Format("| {0} - {1}:| {2} kWh @ ${3}/kWh= ${4}", tx.StartTime.ToString("hh:mm tt", new CultureInfo("en-us")), tx.StopTime.ToString("hh:mm tt", new CultureInfo("en-us")), confirmbill[0].PeriodEnergy.ToString("0.0000"), bill[0].Fee, bill[0].Total); break; } if (bill.Count == 0) { receipt += string.Format("| {0} - {1} @ ${2}/hr= ${3}", feedto.StartTime.ToString("hh:mm tt", new CultureInfo("en-us")), feedto.StopTime.ToString("hh:mm tt", new CultureInfo("en-us")), feedto.Fee.Split('|')[0], chargingCost); break; } if (bill.Count > 1) { var time = startTime.ToString("hh:mm tt", new CultureInfo("en-us")); var tt = bill.Where(x => x.StartTime == time).FirstOrDefault(); confirmbill.Add(tt); if (confirmbill.Count == 1) { confirmbill[0].StartTime = tx.StartTime.ToString("hh:mm tt", new CultureInfo("en-us")); } var stopTimeText = tx.StopTime.ToString("hh:mm tt", new CultureInfo("en-us")); if (confirmbill[confirmbill.Count - 1].StartTime.Contains(stopTimeText.Split(' ')[1])) { var subHourText = (int.Parse(stopTimeText.Split(':')[0])).ToString(); subHourText = subHourText.Length == 1 ? "0" + subHourText : subHourText; if (confirmbill[confirmbill.Count - 1].StartTime.Contains(subHourText)) { confirmbill[confirmbill.Count - 1].EndTime = stopTimeText; } } 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.ToString("0.0000"), confirmbill[confirmbill.Count - 1].Fee, confirmbill[confirmbill.Count - 1].Total); if (confirmbill.Count == 24) break; } startTime = startTime.AddHours(1); } chargingCost = confirmbill.Count > 0 ? confirmbill.Sum(x => x.Total) : chargingCost; receipt += string.Format("|Total Energy Fee : ${0}", chargingCost); receipt += string.Format("|Parking Fee: | {0} - {1}: | {2} @ ${3}/hr= ${4}", feedto.StartTime.ToString("hh:mm tt", new CultureInfo("en-us")), feedto.StopTime.ToString("hh:mm tt", new CultureInfo("en-us")), (totalHours / 1 >= 1) ? string.Format("{0} hours {1} minutes", (int)totalHours / 1, ((totalHours % 1) * 60).ToString("0.0")) : string.Format("{0} minutes", ((totalHours % 1) * 60).ToString("0.0")), parkingFee, parkingCost); receipt += string.Format("|Stop Reason: {0}", tx.StopReason); tx.Cost = chargingCost + parkingCost; if (customerInfo != null && customerInfo.InstantStopTxReport) { var request = new { ChargeBoxId = tx.ChargeBoxId, ConnectorId = tx.ConnectorId, SessionId = tx.Id, MeterStart = tx.MeterStart, MeterStop = tx.MeterStop, IdTag = tx.StartIdTag, StartTime = tx.StartTime.ToString(GlobalConfig.UTC_DATETIMEFORMAT), StopTime = tx.StopTime.ToString(GlobalConfig.UTC_DATETIMEFORMAT), StopReason = tx.StopReasonId < 1 ? "Unknown" : (tx.StopReasonId > 12 ? "Unknown" : ((Reason)tx.StopReasonId).ToString()), Receipt = tx.Receipt, TotalCost = tx.Cost, Fee = tx.Fee }; logger.Debug("completed_session " + JsonConvert.SerializeObject(request)); var response = await httpClient.Post(customerInfo.ApiUrl + "completed_session", new Dictionary() { { "PartnerId",session.CustomerId.ToString()} }, request, customerInfo.ApiKey); var _httpResult = JsonConvert.DeserializeObject(response.Response); logger.Debug("completed_session Response" + response.Response); JObject jo = JObject.Parse(_httpResult.Data); if (jo.ContainsKey("CouponPoint")) { couponPoint = jo["CouponPoint"].Value(); } if (jo.ContainsKey("FarewellMessage")) { farewellMessage = jo["FarewellMessage"].Value(); } } tx.Receipt = receipt; tx.BillingDone = true; 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.Entry(tx).Property(x => x.BillingDone).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 = JsonConvert.SerializeObject(new { chargedEnergy = chargedEnergy, chargingFee = chargingCost, parkTime = (int)stoptime.Subtract(starttime).TotalSeconds, parkingFee = parkingCost, currency = currency, couponPoint = couponPoint, accountBalance = accountBalance - tx.Cost, farewellMessage = farewellMessage }) }) }, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }), SerialNo = Guid.NewGuid().ToString(), InMessage = string.Empty }); ; await db.SaveChangesAsync(); using (var meterdb = new MeterValueDBContext()) { 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)feedto.ConnectorId), new SqlParameter("Value",chargingCost), new SqlParameter("CreatedOn",DateTime.UtcNow), new SqlParameter("ContextId",(int)ReadingContext.Sample_Periodic), new SqlParameter("FormatId",(int)ValueFormat.Raw), new SqlParameter("MeasurandId",(int)Measurand.TotalCost), new SqlParameter("PhaseId", -1), new SqlParameter("LocationId", -1), new SqlParameter("UnitId", -1), new SqlParameter("TransactionId",feedto.Id), }; meterdb.Database.ExecuteSqlCommand(sp, parameter.ToArray()); } using (SqlConnection conn = new SqlConnection(webConnectionString)) { var parameters = new DynamicParameters(); parameters.Add("@IdTag", tx.StartIdTag, DbType.String, ParameterDirection.Input); parameters.Add("@parentIdTag", accountBalance - tx.Cost, DbType.String, ParameterDirection.Input); string strSql = "update [dbo].[LocalListDetail] set parentIdTag =@parentIdTag where ListId = 27 and IdTag=@IdTag; "; await conn.ExecuteAsync(strSql, parameters); } #region 提供給PHA 過CDFA認證 使用 if (tx.CustomerId == Guid.Parse("10C7F5BD-C89A-4E2A-8611-B617E0B41A73")) { var mail_response = new OuterHttpClient().PostFormDataAsync("https://evcb.zerovatech.com/CDFA/" + tx.Id, new Dictionary() { { "email","2"}, { "to","wonderj@phihongusa.com;jessica_tseng@phihong.com.tw"} //{ "to","jessica_tseng@phihong.com.tw"} }, null); Console.WriteLine(JsonConvert.SerializeObject(mail_response)); } #endregion } 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 = JsonConvert.SerializeObject(new { chargedEnergy = chargedEnergy, chargingFee = chargingCost, parkTime = (int)stoptime.Subtract(starttime).TotalSeconds, parkingFee = parkingCost, currency = currency }) }) }, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }), SerialNo = Guid.NewGuid().ToString(), InMessage = string.Empty }); ; await db.SaveChangesAsync(); using (var meterdb = new MeterValueDBContext()) { 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)feedto.ConnectorId), new SqlParameter("Value",chargingCost), new SqlParameter("CreatedOn",DateTime.UtcNow), new SqlParameter("ContextId",(int)ReadingContext.Sample_Periodic), new SqlParameter("FormatId",(int)ValueFormat.Raw), new SqlParameter("MeasurandId",(int)Measurand.ChargingCost), new SqlParameter("PhaseId", -1), new SqlParameter("LocationId", -1), new SqlParameter("UnitId", -1), new SqlParameter("TransactionId",feedto.Id), }; meterdb.Database.ExecuteSqlCommand(sp, parameter.ToArray()); } } } } } } 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(); await db.SaveChangesAsync(); } } } 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(); await db.SaveChangesAsync(); } } } 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(); await db.SaveChangesAsync(); } } } 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(); await db.SaveChangesAsync(); } } } 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(); await db.SaveChangesAsync(); } } } 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 }); } } await db.SaveChangesAsync(); } } 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); } await db.SaveChangesAsync(); } } 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(); await db.SaveChangesAsync(); } } } 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 " + action + " " + 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; } async private Task> GetTransactionSOC(int TxId, DateTime queryDate) { List SOCCollection = new List(); try { using (var _meterDb = new MeterValueDBContext()) { var parameters = new DynamicParameters(); parameters.Add("@TransactionId", TxId, DbType.Int32, ParameterDirection.Input); string strSql = "SELECT [TransactionId],Min(Value) as MinSoC,Max(Value) as MaxSoC " + "FROM [dbo].ConnectorMeterValueRecord" + queryDate.Date.ToString("yyMMdd") + " where TransactionId=@TransactionId and MeasurandId=20 group by [TransactionId]"; var result = await _meterDb.Database.Connection.QueryFirstOrDefaultAsync(strSql, parameters); // SOCCollection = results.Select(decimal.Parse).ToList(); if (result != null) { SOCCollection.Add(result.MaxSoC); SOCCollection.Add(result.MinSoC); } } } catch (Exception ex) { } return SOCCollection; } } }