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.Basic; using EVCB_OCPP.Packet.Messages.Core; using EVCB_OCPP.Packet.Messages.RemoteTrigger; using EVCB_OCPP.WSServer.Dto; using EVCB_OCPP.WSServer.Helper; using EVCB_OCPP.WSServer.Message; using EVCB_OCPP.WSServer.Service; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NLog; using OCPPServer.Protocol; using OCPPServer.SubProtocol; using SuperSocket.SocketBase; using SuperSocket.SocketBase.Config; using System; using System.Collections.Generic; using System.Configuration; using System.Data; using System.Data.Entity; using System.Data.SqlClient; using System.Diagnostics; using System.Linq; using System.Security.Authentication; using System.Threading; using System.Threading.Tasks; using System.Xml.Linq; namespace EVCB_OCPP.WSServer { public class DestroyRequest : IRequest { public string Action { get; set; } public bool TransactionRelated() { return false; } public bool Validate() { return true; } } internal class ProtalServer { #region private fields static private ILogger logger = NLog.LogManager.GetCurrentClassLogger(); private OuterHttpClient httpClient = new OuterHttpClient(); private DateTime lastcheckdt = DateTime.UtcNow.AddSeconds(-20); private Dictionary clientDic = new Dictionary(); private readonly Object _lockClientDic = new object(); private readonly Object _lockConfirmPacketList = new object(); private ProfileHandler profileHandler = new ProfileHandler(); private List needConfirmPacketList = new List(); private DateTime checkUpdateDt = DateTime.UtcNow; private DateTime _CheckFeeDt = DateTime.UtcNow; private DateTime _CheckLBDt = DateTime.UtcNow; private DateTime _CheckDenyListDt = DateTime.UtcNow.AddDays(-1); private LoadingBalanceService _loadingBalanceService = new LoadingBalanceService(); private List _StationInfo = new List(); private List needConfirmActions = new List() { "GetConfiguration", "ChangeConfiguration", "RemoteStartTransaction", "RemoteStopTransaction", "ChangeAvailability", "ClearCache", "DataTransfer", "Reset", "UnlockConnector", "TriggerMessage", "GetDiagnostics", "UpdateFirmware", "GetLocalListVersion", "SendLocalList", "SetChargingProfile", "ClearChargingProfile", "GetCompositeSchedule", "ReserveNow", "CancelReservation", "ExtendedTriggerMessage" }; private List profiles = new List() { new CoreProfile(), new FirmwareManagementProfile(), new ReservationProfile(), new RemoteTriggerProfile(), new SmartChargingProfile(), new LocalAuthListManagementProfile(), new SecurityProfile(), }; private CancellationTokenSource _cts = new CancellationTokenSource(); private CancellationToken _ct; private string webConnectionString = ConfigurationManager.ConnectionStrings["WebDBContext"].ConnectionString; #endregion internal ProtalServer() { _ct = _cts.Token; WarmUpLog(); // DenyModelCheckTrigger(true); } internal void Start() { if (!GlobalConfig.LoadAPPConfig()) { Console.WriteLine("Please check App.Config setting ."); return; } OpenNetwork(); Task serverCommandTask = new Task(ServerMessageTrigger, _ct); serverCommandTask.Start(); Task serverUpdateTask = new Task(ServerUpdateTrigger, _ct); serverUpdateTask.Start(); Task serverSetFeeTask = new Task(ServerSetFeeTrigger, _ct); serverSetFeeTask.Start(); Task serverBeatTask = new Task(HeartBeatCheckTrigger, _ct); serverBeatTask.Start(); Task serverHealthTask = new Task(HealthCheckTrigger, _ct); serverHealthTask.Start(); Task smartChargingTask = new Task(SmartChargingTrigger, _ct); smartChargingTask.Start(); Task denyModelCheckTask = new Task(() => DenyModelCheckTrigger(false), _ct); denyModelCheckTask.Start(); while (true) { var input = Console.ReadLine(); switch (input.ToLower()) { case "stop": Console.WriteLine("Command stop"); Stop(); break; case "gc": Console.WriteLine("Command GC"); GC.Collect(); break; case "lc": { Console.WriteLine("Command List Clients"); Dictionary _copyClientDic = null; lock (_lockClientDic) { _copyClientDic = new Dictionary(clientDic); } var list = _copyClientDic.Select(c => c.Value).ToList(); int i = 1; foreach (var c in list) { Console.WriteLine(i + ":" + c.ChargeBoxId + " " + c.SessionID); i++; } } break; case "lcn": { Console.WriteLine("Command List Customer Name"); Dictionary _copyClientDic = null; lock (_lockClientDic) { _copyClientDic = new Dictionary(clientDic); } var lcn = clientDic.Select(c => c.Value.CustomerName).Distinct().ToList(); int iLcn = 1; foreach (var c in lcn) { Console.WriteLine(iLcn + ":" + c + ":" + clientDic.Where(z => z.Value.CustomerName == c).Count().ToString()); iLcn++; } } break; case "help": Console.WriteLine("Command help!!"); Console.WriteLine("lcn : List Customer Name"); Console.WriteLine("gc : GC Collect"); Console.WriteLine("lc : List Clients"); Console.WriteLine("cls : clear console"); Console.WriteLine("silent : silent"); Console.WriteLine("show : show log"); // logger.Info("rcl : show Real Connection Limit"); break; case "cls": Console.WriteLine("Command clear"); Console.Clear(); break; case "silent": Console.WriteLine("Command silent"); var xe = XElement.Load("NLog.config"); var xns = xe.GetDefaultNamespace(); var minlevelattr = xe.Descendants(xns + "rules").Elements(xns + "logger") .Where(c => c.Attribute("writeTo").Value.Equals("console")).Attributes("minlevel").FirstOrDefault(); if (minlevelattr != null) { minlevelattr.Value = "Warn"; } xe.Save("NLog.config"); break; case "show": Console.WriteLine("Command show"); var xe1 = XElement.Load("NLog.config"); var xns1 = xe1.GetDefaultNamespace(); var minlevelattr1 = xe1.Descendants(xns1 + "rules").Elements(xns1 + "logger") .Where(c => c.Attribute("writeTo").Value.Equals("console")).Attributes("minlevel").FirstOrDefault(); if (minlevelattr1 != null) { minlevelattr1.Value = "trace"; } xe1.Save("NLog.config"); break; case "rcl": break; default: break; } } } internal void Stop() { if (_cts != null) { _cts.Cancel(); } } private void CheckEVSEConfigure(string chargeBoxId) { if (string.IsNullOrEmpty(chargeBoxId)) return; using (var db = new MainDBContext()) { db.ServerMessage.Add(new ServerMessage() { ChargeBoxId = chargeBoxId, CreatedBy = "Server", CreatedOn = DateTime.UtcNow, OutAction = Actions.GetConfiguration.ToString(), OutRequest = JsonConvert.SerializeObject( new GetConfigurationRequest() { key = new List() }, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }), SerialNo = Guid.NewGuid().ToString(), InMessage = string.Empty }); ; db.SaveChanges(); } } private void OpenNetwork() { //載入OCPP Protocol var appServer = new OCPPWSServer(new List() { new OCPPSubProtocol(), new OCPPSubProtocol(" ocpp1.6"), new OCPPSubProtocol("ocpp2.0") }); List llistener = new List(); if (GlobalConfig.GetWS_Port() != 0) { llistener.Add(new ListenerConfig { Ip = System.Net.IPAddress.Any.ToString(), Port = GlobalConfig.GetWS_Port(), Backlog = 100, Security = "None" }); } foreach (var securityport in GlobalConfig.GetWSS_Ports()) { llistener.Add(new ListenerConfig { Ip = System.Net.IPAddress.Any.ToString(), Port = securityport, Backlog = 100, Security = SslProtocols.Tls12.ToString() }); } var config = ConfigurationManager.GetSection("superSocket") as IConfigurationSource; ICertificateConfig Certificate = config.Servers.ElementAt(0).Certificate; IEnumerable listeners = llistener; //設定server config var serverConfig = new ServerConfig { SendingQueueSize = 10, //Port = Convert.ToInt32(2012), //Ip = "172.17.40.13", MaxRequestLength = 204800, //Security = serverSecurity, Certificate = Certificate, Listeners = listeners, // LogAllSocketException = true, KeepAliveTime = 10, // LogBasicSessionActivity = true }; //Setup with listening port if (!appServer.Setup(serverConfig, logFactory: new OCPPLogFactory())) { Console.WriteLine("Failed to setup!"); return; } appServer.NewSessionConnected += AppServer_NewSessionConnected; appServer.SessionClosed += AppServer_SessionClosed; //Try to start the appServer if (!appServer.Start()) { Console.WriteLine("Failed to start!"); Console.ReadKey(); return; } } private void AppServer_SessionClosed(ClientData session, CloseReason value) { WriteMachineLog(session, string.Format("CloseReason: {0}", value), "Connection", ""); RemoveClient(session); } private void AppServer_NewSessionConnected(ClientData session) { logger.Debug(string.Format("{0} NewSessionConnected", session.Path)); try { lock (_lockClientDic) { bool isNotSupported = session.SecWebSocketProtocol.Contains("ocpp1.6") ? false : session.SecWebSocketProtocol.Contains("ocpp2.0") ? false : true; if (isNotSupported) { //logger.Debug(string.Format("ChargeBoxId:{0} SecWebSocketProtocol:{1} NotSupported", session.ChargeBoxId, session.SecWebSocketProtocol)); WriteMachineLog(session, string.Format("SecWebSocketProtocol:{0} NotSupported", session.SecWebSocketProtocol), "Connection", ""); return; } ClientData _removeClient = null; clientDic.TryGetValue(session.ChargeBoxId, out _removeClient); if (_removeClient != null) { WriteMachineLog(_removeClient, "Duplicate Logins", "Connection", ""); _removeClient.Close(CloseReason.ServerShutdown); RemoveClient(_removeClient); } clientDic.Add(session.ChargeBoxId, session); session.m_ReceiveData += new ClientData.OCPPClientDataEventHandler(ReceivedMessage); // logger.Debug("------------New " + (session == null ? "Oops" : session.ChargeBoxId)); WriteMachineLog(session, "NewSessionConnected", "Connection", ""); using (var db = new MainDBContext()) { var machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault(); if (machine != null) { machine.ConnectionType = session.Origin.Contains("https") ? 2 : 1; db.SaveChanges(); } } } } catch (Exception ex) { logger.Error(string.Format("NewSessionConnected Ex: {0}", ex.ToString())); } } async private void ReceivedMessage(ClientData session, string rawdata) { try { BasicMessageHandler msgAnalyser = new BasicMessageHandler(); MessageResult analysisResult = msgAnalyser.AnalysisReceiveData(session, rawdata); WriteMachineLog(session, rawdata, string.Format("{0} {1}", string.IsNullOrEmpty(analysisResult.Action) ? "unknown" : analysisResult.Action, analysisResult.Id == 2 ? "Request" : (analysisResult.Id == 3 ? "Confirmation" : "Error")), analysisResult.Exception == null ? "" : analysisResult.Exception.Message); if (session.ResetSecurityProfile) { logger.Error(string.Format("[{0}] ChargeBoxId:{1} ResetSecurityProfile", DateTime.UtcNow, session.ChargeBoxId)); RemoveClient(session); return; } if (!analysisResult.Success) { //解析RawData就發生錯誤 if (!string.IsNullOrEmpty(analysisResult.CallErrorMsg)) { Send(session, analysisResult.CallErrorMsg, string.Format("{0} {1}", analysisResult.Action, "Error")); } else { if (analysisResult.Message == null) { string replyMsg = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError); string errorMsg = string.Empty; if (analysisResult.Exception != null) { errorMsg = analysisResult.Exception.ToString(); } Send(session, replyMsg, string.Format("{0} {1}", "unknown", "Error"), "EVSE's sent essage has parsed Failed. "); } else { BaseMessage _baseMsg = analysisResult.Message as BaseMessage; string replyMsg = BasicMessageHandler.GenerateCallError(_baseMsg.Id, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError); string errorMsg = string.Empty; if (analysisResult.Exception != null) { errorMsg = analysisResult.Exception.ToString(); } Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg); } } } else { switch (analysisResult.Id) { case BasicMessageHandler.TYPENUMBER_CALL: { if (!session.ISOCPP20) { Actions action = Convertor.GetAction(analysisResult.Action); ProcessRequestMessage(analysisResult, session, action); } else { EVCB_OCPP20.Packet.Features.Actions action = Convertor.GetActionby20(analysisResult.Action); MessageResult result = new MessageResult() { Success = true }; //ocpp20 處理 switch (action) { case EVCB_OCPP20.Packet.Features.Actions.BootNotification: { EVCB_OCPP20.Packet.Messages.BootNotificationRequest _request = (EVCB_OCPP20.Packet.Messages.IRequest)analysisResult.Message as EVCB_OCPP20.Packet.Messages.BootNotificationRequest; var confirm = new EVCB_OCPP20.Packet.Messages.BootNotificationResponse() { CurrentTime = DateTime.UtcNow, Interval = 180, Status = EVCB_OCPP20.Packet.DataTypes.EnumTypes.RegistrationStatusEnumType.Pending }; result.Message = confirm; result.Success = true; string response = BasicMessageHandler.GenerateConfirmationofOCPP20(analysisResult.UUID, (EVCB_OCPP20.Packet.Messages.IConfirmation)result.Message); Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Response"), result.Exception == null ? string.Empty : result.Exception.ToString()); var request = new EVCB_OCPP20.Packet.Messages.SetNetworkProfileRequest() { ConfigurationSlot = 1, ConnectionData = new EVCB_OCPP20.Packet.DataTypes.NetworkConnectionProfileType() { OcppVersion = EVCB_OCPP20.Packet.DataTypes.EnumTypes.OCPPVersionEnumType.OCPP20, OcppTransport = EVCB_OCPP20.Packet.DataTypes.EnumTypes.OCPPTransportEnumType.JSON, MessageTimeout = 30, OcppCsmsUrl = session.UriScheme == "ws" ? GlobalConfig.OCPP20_WSUrl : GlobalConfig.OCPP20_WSSUrl, OcppInterface = EVCB_OCPP20.Packet.DataTypes.EnumTypes.OCPPInterfaceEnumType.Wired0 } }; var uuid = session.queue20.store(request); string requestText = BasicMessageHandler.GenerateRequestofOCPP20(uuid, "SetNetworkProfile", request); Send(session, requestText, "SetNetworkProfile"); } break; default: { logger.Error(string.Format("We don't implement messagetype:{0} of raw data :{1} by {2}", analysisResult.Id, rawdata, session.ChargeBoxId)); } break; } } } break; case BasicMessageHandler.TYPENUMBER_CALLRESULT: { if (!session.ISOCPP20) { Actions action = Convertor.GetAction(analysisResult.Action); ProcessConfirmationMessage(analysisResult, session, action); } else { EVCB_OCPP20.Packet.Features.Actions action = Convertor.GetActionby20(analysisResult.Action); MessageResult result = new MessageResult() { Success = true }; //ocpp20 處理 switch (action) { case EVCB_OCPP20.Packet.Features.Actions.SetNetworkProfile: { EVCB_OCPP20.Packet.Messages.SetNetworkProfileResponse response = (EVCB_OCPP20.Packet.Messages.IConfirmation)analysisResult.Message as EVCB_OCPP20.Packet.Messages.SetNetworkProfileResponse; if (response.Status == EVCB_OCPP20.Packet.DataTypes.EnumTypes.SetNetworkProfileStatusEnumType.Accepted) { var request = new EVCB_OCPP20.Packet.Messages.SetVariablesRequest() { SetVariableData = new List() { new EVCB_OCPP20.Packet.DataTypes.SetVariableDataType() { Component=new EVCB_OCPP20.Packet.DataTypes.ComponentType() { Name="OCPPCommCtrlr", }, AttributeType= EVCB_OCPP20.Packet.DataTypes.EnumTypes.AttributeEnumType.Actual, AttributeValue= JsonConvert.SerializeObject(new List(){ 1 }), Variable=new EVCB_OCPP20.Packet.DataTypes.VariableType() { Name="NetworkConfigurationPriority", } } } }; var uuid = session.queue20.store(request); string requestText = BasicMessageHandler.GenerateRequestofOCPP20(uuid, "SetVariables", request); Send(session, requestText, "SetVariables"); } } break; case EVCB_OCPP20.Packet.Features.Actions.SetVariables: { EVCB_OCPP20.Packet.Messages.SetVariablesResponse response = (EVCB_OCPP20.Packet.Messages.IConfirmation)analysisResult.Message as EVCB_OCPP20.Packet.Messages.SetVariablesResponse; if (response.SetVariableResult[0].AttributeStatus == EVCB_OCPP20.Packet.DataTypes.EnumTypes.SetVariableStatusEnumType.RebootRequired) { var request = new EVCB_OCPP20.Packet.Messages.ResetRequest() { Type = EVCB_OCPP20.Packet.DataTypes.EnumTypes.ResetEnumType.OnIdle }; var uuid = session.queue20.store(request); string requestText = BasicMessageHandler.GenerateRequestofOCPP20(uuid, "Reset", request); Send(session, requestText, "Reset"); } } break; default: { logger.Error(string.Format("We don't implement messagetype:{0} of raw data :{1} by {2}", analysisResult.Id, rawdata, session.ChargeBoxId)); } break; } } } break; case BasicMessageHandler.TYPENUMBER_CALLERROR: { //只處理 丟出Request 收到Error的訊息 if (analysisResult.Success && analysisResult.Message != null) { Actions action = Convertor.GetAction(analysisResult.Action); ProcessErrorMessage(analysisResult, session, action); } } break; default: { logger.Error(string.Format("Can't analyze messagetype:{0} of raw data :{1} by {2}", analysisResult.Id, rawdata, session.ChargeBoxId)); } break; } } await Task.Delay(10); } catch (Exception ex) { if (ex.InnerException != null) { logger.Error(string.Format("{0} **Inner Exception :{1} ", session.ChargeBoxId + rawdata, ex.ToString())); } else { logger.Error(string.Format("{0} **Exception :{1} ", session.ChargeBoxId, ex.ToString())); } } } async private void ProcessRequestMessage(MessageResult analysisResult, ClientData session, Actions action) { BasicMessageHandler msgAnalyser = new BasicMessageHandler(); if (!session.IsCheckIn && action != Actions.BootNotification) { string response = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.GenericError, OCPPErrorDescription.NotChecked); Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Error")); } else { var profileName = profiles.Where(x => x.IsExisted(analysisResult.Action)).Select(x => x.Name).FirstOrDefault(); switch (profileName) { case "Core": { var replyResult = await profileHandler.ExecuteCoreRequest(action, session, (IRequest)analysisResult.Message).ConfigureAwait(false); if (replyResult.Success) { string response = BasicMessageHandler.GenerateConfirmation(analysisResult.UUID, (IConfirmation)replyResult.Message); Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Confirmation"), replyResult.Exception == null ? string.Empty : replyResult.Exception.ToString()); if (action == Actions.BootNotification && replyResult.Message is BootNotificationConfirmation) { session.IsCheckIn = true; if (((BootNotificationConfirmation)replyResult.Message).status == Packet.Messages.SubTypes.RegistrationStatus.Accepted) { CheckEVSEConfigure(session.ChargeBoxId); if (session.CustomerId == new Guid("298918C0-6BB5-421A-88CC-4922F918E85E") || session.CustomerId == new Guid("9E6BFDCC-09FB-4DAB-A428-43FE507600A3")) { using (var db = new MainDBContext()) { db.ServerMessage.Add(new ServerMessage() { ChargeBoxId = session.ChargeBoxId, CreatedBy = "Server", CreatedOn = DateTime.UtcNow, OutAction = Actions.ChangeConfiguration.ToString(), OutRequest = JsonConvert.SerializeObject( new ChangeConfigurationRequest() { key = "TimeOffset", value = "+08:00" }, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }), SerialNo = Guid.NewGuid().ToString(), InMessage = string.Empty }); db.SaveChanges(); } } } else { using (var db = new MainDBContext()) { var machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault(); if (machine != null) { if (machine.ConnectorType.Contains("6") || machine.ConnectorType.Contains("7") || machine.ConnectorType.Contains("8") || machine.ConnectorType.Contains("9")) { session.IsAC = false; } machine.ConnectionType = session.Origin.Contains("https") ? 2 : 1; db.SaveChanges(); } } await SetDefaultFee(session); } } if (action == Actions.Authorize && replyResult.Message is AuthorizeConfirmation) { var authorizeRequest = (IRequest)analysisResult.Message as AuthorizeRequest; if (session.UserDisplayPrices.ContainsKey(authorizeRequest.idTag)) { 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 = "SetUserPrice", vendorId = "Phihong Technology", data = JsonConvert.SerializeObject( new { idToken = authorizeRequest.idTag, price = session.UserDisplayPrices[authorizeRequest.idTag] }) }, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }), SerialNo = Guid.NewGuid().ToString(), InMessage = string.Empty }); db.SaveChanges(); } } } } else { if (action == Actions.StopTransaction && replyResult.CallErrorMsg == "Reject Response Message") { //do nothing logger.Warn(replyResult.Exception.ToString()); } else { string response = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError); string errorMsg = replyResult.Exception != null ? replyResult.Exception.ToString() : string.Empty; Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg); } } if (action == Actions.StartTransaction) { var stationId = _loadingBalanceService.GetStationIdByMachineId(session.MachineId); var _powerDic = await _loadingBalanceService.GetSettingPower(stationId); if (_powerDic != null) { foreach (var kv in _powerDic) { try { if (kv.Value.HasValue) { profileHandler.SetChargingProfile(kv.Key, kv.Value.Value, Packet.Messages.SubTypes.ChargingRateUnitType.W); } } catch (Exception ex) { logger.Error(string.Format("Set Profile Exception: {0}", ex.ToString())); } } } } if (action == Actions.StopTransaction) { var stationId = _loadingBalanceService.GetStationIdByMachineId(session.MachineId); var _powerDic = await _loadingBalanceService.GetSettingPower(stationId); if (_powerDic != null) { foreach (var kv in _powerDic) { try { if (kv.Value.HasValue) { profileHandler.SetChargingProfile(kv.Key, kv.Value.Value, Packet.Messages.SubTypes.ChargingRateUnitType.W); } } catch (Exception ex) { logger.Error(string.Format("Set Profile Exception: {0}", ex.ToString())); } } } } } break; case "FirmwareManagement": { var replyResult = await profileHandler.ExecuteFirmwareManagementRequest(action, session, (IRequest)analysisResult.Message); if (replyResult.Success) { string response = BasicMessageHandler.GenerateConfirmation(analysisResult.UUID, (IConfirmation)replyResult.Message); Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Confirmation", replyResult.Exception == null ? string.Empty : replyResult.Exception.ToString())); } else { string response = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError); string errorMsg = replyResult.Exception != null ? replyResult.Exception.ToString() : string.Empty; Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg); } } break; case "Security": { var replyResult = profileHandler.ExecuteSecurityRequest(action, session, (IRequest)analysisResult.Message); if (replyResult.Success) { string response = BasicMessageHandler.GenerateConfirmation(analysisResult.UUID, (IConfirmation)replyResult.Message); Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Confirmation", replyResult.Exception == null ? string.Empty : replyResult.Exception.ToString())); } else { string response = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError); string errorMsg = replyResult.Exception != null ? replyResult.Exception.ToString() : string.Empty; Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg); } } break; default: { string replyMsg = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError); string errorMsg = string.Format("Couldn't find action name: {0} of profile", action); Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg); } break; } } } async private void ProcessConfirmationMessage(MessageResult analysisResult, ClientData session, Actions action) { BasicMessageHandler msgAnalyser = new BasicMessageHandler(); if (ReConfirmMessage(analysisResult)) { var profileName = profiles.Where(x => x.IsExisted(analysisResult.Action)).Select(x => x.Name).FirstOrDefault(); MessageResult confirmResult = null; switch (profileName) { case "Core": { confirmResult = await profileHandler.ExecuteCoreConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId); } break; case "FirmwareManagement": { confirmResult = profileHandler.ExecuteFirmwareManagementConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId); } break; case "RemoteTrigger": { confirmResult = profileHandler.ExecuteRemoteTriggerConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId); } break; case "Reservation": { confirmResult = profileHandler.ExecuteReservationConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId); } break; case "LocalAuthListManagement": { confirmResult = profileHandler.ExecuteLocalAuthListManagementConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId); } break; case "SmartCharging": { confirmResult = profileHandler.ExecuteSmartChargingConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId); } break; case "Security": { confirmResult = profileHandler.ExecuteSecurityConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId); } break; default: { string replyMsg = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError); string errorMsg = string.Format("Couldn't find action name: {0} of profile", action); Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg); } break; } if (confirmResult == null || !confirmResult.Success) { logger.Error(string.Format("Action:{0} MessageId:{1} ExecuteConfirm Error:{2} ", analysisResult.Action, analysisResult.UUID, confirmResult.Exception.ToString())); } } else { string replyMsg = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError); string errorMsg = string.Format("Action:{0} MessageId:{1} didn't exist in confirm message", analysisResult.Action, analysisResult.UUID); Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg); } } private void ProcessErrorMessage(MessageResult analysisResult, ClientData session, Actions action) { BasicMessageHandler msgAnalyser = new BasicMessageHandler(); if (ReConfirmMessage(analysisResult)) { var profileName = profiles.Where(x => x.IsExisted(analysisResult.Action)).Select(x => x.Name).FirstOrDefault(); switch (profileName) { case "Core": { profileHandler.ReceivedCoreError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId); } break; case "FirmwareManagement": { profileHandler.ReceivedFirmwareManagementError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId); } break; case "RemoteTrigger": { profileHandler.ReceivedRemoteTriggerError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId); } break; case "Reservation": { profileHandler.ExecuteReservationError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId); } break; case "LocalAuthListManagement": { profileHandler.ReceivedLocalAuthListManagementError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId); } break; case "SmartCharging": { profileHandler.ReceivedSmartChargingError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId); } break; default: { string replyMsg = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError); string errorMsg = string.Format("Couldn't find action name: {0} of profile", action); Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg); } break; } } else { string replyMsg = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError); string errorMsg = string.Format("Action:{0} MessageId:{1} didn't exist in confirm message", analysisResult.Action, analysisResult.UUID); Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg); } } private void Send(ClientData session, string msg, string messageType, string errorMsg = "") { try { if (session != null) { WriteMachineLog(session, msg, messageType, errorMsg, true); session.Send(msg); } } catch (Exception ex) { logger.Error(string.Format("Send Ex:{0}", ex.ToString())); } } async private void DenyModelCheckTrigger(bool warmup) { for (; ; ) { if (_ct.IsCancellationRequested) { break; } try { var min_Interval = (DateTime.UtcNow - _CheckDenyListDt).TotalMinutes; if (min_Interval > 5) { _CheckDenyListDt = DateTime.UtcNow; using (SqlConnection conn = new SqlConnection(webConnectionString)) { string strSql = "SELECT [Value] FROM [dbo].[KernelConfig] " + "where SystemKey = 'DenyModelNames'; "; var result = await conn.QueryAsync(strSql); GlobalConfig.DenyModelNames = result.FirstOrDefault().Split(',').ToList(); // logger.Debug(string.Format("Current DenyList:[{0}]", string.Join(",", GlobalConfig.DenyModelNames))); } if (!string.IsNullOrEmpty(GlobalConfig.DenyModelNames[0])) { Dictionary _copyClientDic = null; lock (_lockClientDic) { _copyClientDic = new Dictionary(clientDic); } foreach (var denyName in GlobalConfig.DenyModelNames) { var removeClients = _copyClientDic.Where(x => x.Key.StartsWith(denyName)).Select(x => x.Value).ToList(); foreach (var session in removeClients) { Console.WriteLine(string.Format("Server forced to shut down ChargeBox ({0}: Reason: DenyModelName-{1}", session.ChargeBoxId, denyName)); RemoveClient(session); } } } } await Task.Delay(500); } catch (Exception ex) { // logger.Error(string.Format("DenyModelCheckTrigger Ex:{0}", ex.ToString())); } if (warmup) break; } } async private void ServerUpdateTrigger() { for (; ; ) { if (_ct.IsCancellationRequested) { break; } var min_Interval = (DateTime.UtcNow - checkUpdateDt).TotalMinutes; if (min_Interval > 3) { BasicMessageHandler msgAnalyser = new BasicMessageHandler(); Dictionary _copyClientDic = null; lock (_lockClientDic) { _copyClientDic = new Dictionary(clientDic); } checkUpdateDt = DateTime.UtcNow; using (var db = new MainDBContext()) { var needUpdateChargers = db.Machine.Where(x => x.FW_AssignedVersion.HasValue == true && x.FW_AssignedVersion != x.FW_VersionReport && x.Online == true) .Select(x => x.ChargeBoxId).AsNoTracking().ToList(); foreach (var chargeBoxId in needUpdateChargers) { try { ClientData session; if (_copyClientDic.TryGetValue(chargeBoxId, out session)) { string requestId = Guid.NewGuid().ToString(); if (session.IsCheckIn && !session.ISOCPP20) { var _request = new TriggerMessageRequest() { requestedMessage = Packet.Messages.SubTypes.MessageTrigger.FirmwareStatusNotification }; var uuid = session.queue.store(_request); string rawRequest = BasicMessageHandler.GenerateRequest(uuid, _request.Action, _request); Send(session, rawRequest, string.Format("{0} {1}", _request.Action, "Request"), ""); #region OCTT ,測試韌體更新方式 //--------------------> OCTT ,測試韌體更新方式 //{ // var machine = db.Machine.Where(x => x.FW_AssignedMachineVersionId.HasValue == true && // x.FW_AssignedMachineVersionId != x.FW_VersionReport && x.ChargeBoxId == session.ChargeBoxId) // .Select(x => new { x.Id, x.FW_AssignedMachineVersionId }).FirstOrDefault(); // if (machine != null) // { // var mv = db.MachineVersion.Include(c => c.PublishVersion) // .Include(c => c.PublishVersion.PublishVersionFiles) // .Include(c => c.PublishVersion.PublishVersionFiles.Select(z => z.UploadFile)) // .Where(c => c.Id == machine.FW_AssignedMachineVersionId.Value).First(); // string downloadUrl = mv.PublishVersion.PublishVersionFiles.FirstOrDefault().UploadFile.FileUrl; // var _updateFWrequest = new UpdateFirmwareRequest() // { // location = new Uri(downloadUrl), // retries = 3, // retrieveDate = DateTime.UtcNow, // retryInterval = 10 // }; // db.MachineOperateRecord.Add(new MachineOperateRecord() // { // CreatedOn = DateTime.UtcNow, // ChargeBoxId = session.ChargeBoxId, // SerialNo = requestId, // RequestContent = JsonConvert.SerializeObject(_updateFWrequest, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }), // EVSE_Status = 0, // EVSE_Value = "Fw Version:" + machine.FW_AssignedMachineVersionId, // Status = 0, // RequestType = 0, // }); // db.ServerMessage.Add(new ServerMessage() // { // ChargeBoxId = session.ChargeBoxId, // CreatedBy = "Server", // CreatedOn = DateTime.UtcNow, // OutAction = _updateFWrequest.Action.ToString(), // OutRequest = JsonConvert.SerializeObject(_updateFWrequest, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }), // SerialNo = requestId, // InMessage = string.Empty // }); // db.SaveChanges(); // } //} #endregion } } } catch (Exception ex) { logger.Error(string.Format("serverUpdateTrigger ChargeBoxId:{0} Ex:{1}", chargeBoxId, ex.ToString())); } } } await Task.Delay(1000); } } } async private void ServerMessageTrigger() { for (; ; ) { if (_ct.IsCancellationRequested) { break; } try { RemoveConfirmMessage(); BasicMessageHandler msgAnalyser = new BasicMessageHandler(); using (var db = new MainDBContext()) { DateTime startDt = DateTime.UtcNow.AddSeconds(-30); DateTime dt = new DateTime(1991, 1, 1); DateTime currentTime = DateTime.UtcNow; var commandList = db.ServerMessage.Where(c => c.ReceivedOn == dt && c.UpdatedOn == dt && c.CreatedOn >= startDt && c.CreatedOn <= currentTime).AsNoTracking().ToList(); //處理主機傳送的有指令 var cmdMachineList = commandList.Select(c => c.ChargeBoxId).Distinct().ToList(); if (commandList.Count > 0) { // Console.WriteLine(string.Format("Now:{0} commandList Count:{1} ", DateTime.UtcNow.ToString("yyyy/MM/dd HH:mm:ss"), commandList.Count)); } var resendList = GetResendMessage(); foreach (var resendItem in resendList) { ClientData session; if (clientDic.TryGetValue(resendItem.ChargePointSerialNumber, out session)) { if (DateTime.UtcNow.Subtract(resendItem.SentOn).TotalSeconds > 1) { resendItem.SentTimes--; resendItem.SentOn = DateTime.UtcNow; Send(session, resendItem.SentMessage, string.Format("{0} {1}", resendItem.SentAction, "Request"), ""); } } } foreach (var charger_SN in cmdMachineList) { ClientData session; string uuid = string.Empty; if (clientDic.TryGetValue(charger_SN, out session)) { //logger.Debug(string.Format("charger_SN:{0} startDt:{1} CreatedOn:{2}", charger_SN, startDt.ToString("yyyy/MM/dd HH:mm:ss"), DateTime.UtcNow.ToString("yyyy/MM/dd HH:mm:ss"))); if (session.IsCheckIn && !session.ISOCPP20) { string rawRequest = string.Empty; var cmdList = commandList.Where(c => c.ChargeBoxId == charger_SN).ToList(); foreach (var item in cmdList) { IRequest request = null; Actions action = Actions.None; Enum.TryParse(item.OutAction, out action); Type _RequestType = null; for (int i = 0; i < profiles.Count; i++) { var feature = profiles[i].GetFeaturebyAction(item.OutAction); if (feature != null) { _RequestType = feature.GetRequestType(); break; } } if (_RequestType != null && item.CreatedBy != "Destroyer") { request = JsonConvert.DeserializeObject(item.OutRequest, _RequestType) as IRequest; uuid = session.queue.store(request); rawRequest = BasicMessageHandler.GenerateRequest(uuid, item.OutAction, request); Send(session, rawRequest, string.Format("{0} {1}", action, "Request"), ""); } if (item.CreatedBy == "Destroyer") { if (_RequestType != null) { request = Activator.CreateInstance(_RequestType) as IRequest; uuid = session.queue.store(request); rawRequest = BasicMessageHandler.GenerateDestroyRequest(uuid, item.OutAction, item.OutRequest); Send(session, rawRequest, string.Format("{0} {1}", action, "Request"), ""); } else { rawRequest = BasicMessageHandler.GenerateDestroyRequest(Guid.NewGuid().ToString(), item.OutAction, item.OutRequest); Send(session, rawRequest, string.Format("{0} {1}", action, "Request"), ""); } } AddConfirmMessage(charger_SN, item.Id, item.SerialNo, item.OutAction, uuid, item.CreatedBy, rawRequest); #region 更新資料表單一欄位 var _UpdatedItem = new ServerMessage() { Id = item.Id, UpdatedOn = DateTime.UtcNow }; db.Configuration.AutoDetectChangesEnabled = false;//自動呼叫DetectChanges()比對所有的entry集合的每一個屬性Properties的新舊值 db.Configuration.ValidateOnSaveEnabled = false;// 因為Entity有些欄位必填,若不避開會有Validate錯誤 // var _UpdatedItem = db.ServerMessage.Where(x => x.Id == item.Id).FirstOrDefault(); db.ServerMessage.Attach(_UpdatedItem); _UpdatedItem.UpdatedOn = DateTime.UtcNow; db.Entry(_UpdatedItem).Property(x => x.UpdatedOn).IsModified = true;// 可以直接使用這方式強制某欄位要更新,只是查詢集合耗效能而己 db.SaveChanges(); #endregion await Task.Delay(100); } } } } } await Task.Delay(500); } catch (Exception ex) { logger.Error(string.Format("ServerMessageTrigger Ex:{0}", ex.ToString())); } } } async private void HeartBeatCheckTrigger() { for (; ; ) { if (_ct.IsCancellationRequested) { break; } try { // if (DateTime.UtcNow.Subtract(lastcheckdt).TotalSeconds > 30) { // lastcheckdt = DateTime.UtcNow; Stopwatch watch = new Stopwatch(); Dictionary _copyClientDic = null; lock (_lockClientDic) { _copyClientDic = new Dictionary(clientDic); } var cdt = DateTime.UtcNow; var clients = _copyClientDic.Where(x => x.Value.LastActiveTime > cdt.AddSeconds(-120)).Select(x => x.Value).ToList(); watch.Start(); foreach (var session in clients) { using (var db = new MainDBContext()) { using (var transaction = db.Database.BeginTransaction()) { try { var machine = new Machine() { Id = session.MachineId }; if (machine != null) { db.Configuration.AutoDetectChangesEnabled = false; db.Configuration.ValidateOnSaveEnabled = false; db.Machine.Attach(machine); machine.HeartbeatUpdatedOn = DateTime.UtcNow; machine.ConnectionType = session.UriScheme.Equals("wss") ? 2 : 1; db.Entry(machine).Property(x => x.HeartbeatUpdatedOn).IsModified = true; db.Entry(machine).Property(x => x.ConnectionType).IsModified = true;                                             //await db.SaveChangesAsync();                                             db.SaveChanges(); transaction.Commit(); } } catch (Exception ex) { transaction.Rollback(); } } } } watch.Stop(); if (watch.ElapsedMilliseconds / 1000 > 5) { logger.Fatal("Update HeartBeatCheckTrigger cost " + watch.ElapsedMilliseconds / 1000 + " seconds."); } } await Task.Delay(10000); } catch (Exception ex) { Console.WriteLine("***********************************************************"); logger.Error(string.Format("HeartBeatCheckTrigger Ex:{0}", ex.ToString())); } } } async private void ServerSetFeeTrigger() { for (; ; ) { if (_ct.IsCancellationRequested) { break; } var min_Interval = (DateTime.UtcNow - _CheckFeeDt).TotalMinutes; if (min_Interval > 1) { BasicMessageHandler msgAnalyser = new BasicMessageHandler(); Dictionary _copyClientDic = null; lock (_lockClientDic) { _copyClientDic = new Dictionary(clientDic); } _CheckFeeDt = DateTime.UtcNow; foreach (var item in _copyClientDic) { try { ClientData session = item.Value; if (session.IsCheckIn) { string displayPriceText = await SetDefaultFee(session); if (!string.IsNullOrEmpty(displayPriceText) && displayPriceText != session.DisplayPrice) { clientDic[item.Key].DisplayPrice = displayPriceText; using (var db = new MainDBContext()) { db.ServerMessage.Add(new ServerMessage() { ChargeBoxId = session.ChargeBoxId, CreatedBy = "Server", CreatedOn = DateTime.UtcNow, OutAction = Actions.ChangeConfiguration.ToString(), OutRequest = JsonConvert.SerializeObject( new ChangeConfigurationRequest() { key = "DefaultPrice", value = clientDic[item.Key].DisplayPrice }, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }), SerialNo = Guid.NewGuid().ToString(), InMessage = string.Empty }); ; if (session.CustomerId == new Guid("10C7F5BD-C89A-4E2A-8611-B617E0B41A73")) { db.ServerMessage.Add(new ServerMessage() { ChargeBoxId = session.ChargeBoxId, CreatedBy = "Server", CreatedOn = DateTime.UtcNow, OutAction = Actions.ChangeConfiguration.ToString(), OutRequest = JsonConvert.SerializeObject( new ChangeConfigurationRequest() { key = "ConnectionTimeOut", value = "120" }, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }), SerialNo = Guid.NewGuid().ToString(), InMessage = string.Empty }); db.ServerMessage.Add(new ServerMessage() { ChargeBoxId = session.ChargeBoxId, CreatedBy = "Server", CreatedOn = DateTime.UtcNow, OutAction = Actions.ChangeConfiguration.ToString(), OutRequest = JsonConvert.SerializeObject( new ChangeConfigurationRequest() { key = "MeterValueSampleInterval", value = "3" }, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }), SerialNo = Guid.NewGuid().ToString(), InMessage = string.Empty }); } await db.SaveChangesAsync(); } } } } catch (Exception ex) { logger.Error(string.Format("ServerSetFeeTrigger ChargeBoxId:{0} Ex:{1}", item.Key, ex.ToString())); } } } await Task.Delay(1000); } } async private void SmartChargingTrigger() { for (; ; ) { if (_ct.IsCancellationRequested) { break; } var min_Interval = (DateTime.UtcNow - _CheckLBDt).TotalMinutes; if (min_Interval > 1) { List stations = null; using (SqlConnection conn = new SqlConnection(webConnectionString)) { string strSql = "SELECT[Id],[LBMode],[LBCurrent] as Availability FROM [dbo].[Station] " + "where LBMode = 1; "; var result = await conn.QueryAsync(strSql); stations = result.ToList(); } foreach (var station in stations) { var compareStation = _StationInfo.Where(x => x.Id == station.Id).FirstOrDefault(); if (compareStation == null || (station.Id == compareStation.Id && station.Availability != compareStation.Availability)) { var _powerDic = await _loadingBalanceService.GetSettingPower(station.Id); if (_powerDic != null) { foreach (var kv in _powerDic) { try { if (kv.Value.HasValue) { profileHandler.SetChargingProfile(kv.Key, kv.Value.Value, Packet.Messages.SubTypes.ChargingRateUnitType.W); } } catch (Exception ex) { logger.Error(string.Format("Set Profile Exception: {0}", ex.ToString())); } } } } } _StationInfo = stations; _CheckLBDt = DateTime.UtcNow; } await Task.Delay(1000); } } async private Task SetDefaultFee(ClientData client) { string displayPriceText = string.Empty; string charingPriceText = string.Empty; if (string.IsNullOrEmpty(client.ChargeBoxId)) return displayPriceText; try { using (SqlConnection conn = new SqlConnection(webConnectionString)) { var parameters = new DynamicParameters(); parameters.Add("@MachineId", client.MachineId, DbType.String, ParameterDirection.Input); string displayPricestrSql = ""; string strSql = ""; if (client.IsAC) { displayPricestrSql = " SELECT [AC_BillingMethod] as BillingMethod,[AC_FeeName] as FeeName,[AC_Fee] as ChargingFeebyHour" + " ,[AC_ParkingFee] as ParkingFee, [Currency] FROM[StationMachine] left join[dbo].[Station]" + " on[StationMachine].StationId = Station.[Id] where StationMachine.MachineId=@MachineId and Station.IsBilling=1; "; strSql = " SELECT CAST( [StartTime] as varchar(5)) StartTime,CAST( [EndTime] as varchar(5)) EndTime,[Fee] FROM[StationMachine] left join [dbo].[StationFee]" + " on[StationMachine].StationId = StationFee.StationId where StationMachine.MachineId =@MachineId and StationFee.IsAC=1; "; } else { displayPricestrSql = " SELECT [DC_BillingMethod] as BillingMethod,[DC_FeeName] as FeeName,[DC_Fee] as ChargingFeebyHour" + " ,[DC_ParkingFee] as ParkingFee, [Currency] FROM[StationMachine] left join[dbo].[Station]" + " on[StationMachine].StationId = Station.[Id] where StationMachine.MachineId=@MachineId and Station.IsBilling=1; "; strSql = " SELECT CAST( [StartTime] as varchar(5)) StartTime,CAST( [EndTime] as varchar(5)) EndTime,[Fee] FROM[StationMachine] left join [dbo].[StationFee]" + " on[StationMachine].StationId = StationFee.StationId where StationMachine.MachineId =@MachineId and StationFee.IsAC=0; "; } var result = await conn.QueryAsync(displayPricestrSql, parameters); if (result.Count() == 0) { return string.Empty; } var stationPrice = result.First(); if (stationPrice.BillingMethod == 1) { var chargingPriceResult = await conn.QueryAsync(strSql, parameters); client.ChargingPrices = chargingPriceResult.ToList(); if (string.IsNullOrEmpty(client.ChargingPrices[0].StartTime)) { client.ChargingPrices = new List(); } } displayPriceText = stationPrice.FeeName; client.BillingMethod = stationPrice.BillingMethod; client.Currency = stationPrice.Currency; client.ChargingFeebyHour = stationPrice.ChargingFeebyHour; client.ParkingFee = stationPrice.ParkingFee; client.IsBilling = true; } } catch (Exception ex) { logger.Error("SetDefaultFee", ex.ToString()); } return displayPriceText; } async private void HealthCheckTrigger() { for (; ; ) { if (_ct.IsCancellationRequested) { break; } try { Dictionary _copyClientDic = null; lock (_lockClientDic) { _copyClientDic = new Dictionary(clientDic); } var removeClients = _copyClientDic.Where(x => x.Value.LastActiveTime < DateTime.UtcNow.AddSeconds(-300)).Select(x => x.Value).ToList(); foreach (var session in removeClients) { Console.WriteLine(string.Format("Server forced to shut down ChargeBox ({0}: LastActiveTime{1})", session.ChargeBoxId, session.LastActiveTime)); RemoveClient(session); } await Task.Delay(60000); } catch (Exception ex) { logger.Error(string.Format("HealthAlarmTrigger Ex:{0}", ex.ToString())); } } } private List GetResendMessage() { List sendMessages = new List(); lock (_lockConfirmPacketList) { sendMessages = needConfirmPacketList.Where(x => x.SentTimes > 1 && x.CreatedBy == "Server").ToList(); } return sendMessages; } private void AddConfirmMessage(string chargePointSerialNumber, int table_id, string requestId, string action, string msg_id, string createdBy, string sendMessage) { NeedConfirmMessage _needConfirmMsg = new NeedConfirmMessage(); _needConfirmMsg.Id = table_id; _needConfirmMsg.SentAction = action; _needConfirmMsg.SentOn = DateTime.UtcNow; _needConfirmMsg.SentTimes = 4; _needConfirmMsg.ChargePointSerialNumber = chargePointSerialNumber; _needConfirmMsg.RequestId = requestId; _needConfirmMsg.SentUniqueId = msg_id; _needConfirmMsg.CreatedBy = createdBy; _needConfirmMsg.SentMessage = sendMessage; if (needConfirmActions.Contains(action)) { lock (_lockConfirmPacketList) { needConfirmPacketList.Add(_needConfirmMsg); } } } private void RemoveConfirmMessage() { var before10Mins = DateTime.UtcNow.AddMinutes(-10); lock (_lockConfirmPacketList) { var removeList = needConfirmPacketList.Where(x => x.SentTimes == 0 || x.SentOn < before10Mins).ToList(); foreach (var item in removeList) { needConfirmPacketList.Remove(item); } } } private bool ReConfirmMessage(MessageResult analysisResult) { bool confirmed = false; if (needConfirmActions.Contains(analysisResult.Action)) { NeedConfirmMessage foundRequest = null; lock (_lockConfirmPacketList) { foundRequest = needConfirmPacketList.Where(x => x.SentUniqueId == analysisResult.UUID).FirstOrDefault(); } if (foundRequest != null && foundRequest.Id > 0) { foundRequest.SentTimes = 0; foundRequest.SentInterval = 0; analysisResult.RequestId = foundRequest.RequestId; using (var db = new MainDBContext()) { var sc = db.ServerMessage.Where(x => x.Id == foundRequest.Id).FirstOrDefault(); sc.InMessage = JsonConvert.SerializeObject(analysisResult.Message, Formatting.None); sc.ReceivedOn = DateTime.UtcNow; db.SaveChanges(); // Console.WriteLine(string.Format("Now:{0} ServerMessage Id:{1} ", DateTime.UtcNow.ToString("yyyy/MM/dd HH:mm:ss"), foundRequest.Id)); } confirmed = true; } else if (analysisResult.Action == Actions.TriggerMessage.ToString()) { confirmed = true; } else { logger.Error(string.Format("Received no record Action:{0} MessageId:{1} ", analysisResult.Action, analysisResult.UUID)); } } return confirmed; } private void RemoveClient(ClientData session) { if (session != null) { if (!string.IsNullOrEmpty(session.MachineId)) logger.Trace("RemoveClient[" + session.ChargeBoxId + "]"); if (session.Connected) { session.Close(CloseReason.ServerShutdown); } RemoveClientDic(session); try { session.m_ReceiveData -= new ClientData.OCPPClientDataEventHandler(ReceivedMessage); // session.Close(CloseReason.ServerShutdown); } catch (Exception ex) { //logger.Warn("Close client socket error!!"); logger.Warn(string.Format("Close client socket error!! {0} Msg:{1}", session.ChargeBoxId, ex.Message)); } if (session != null) { session = null; } } } private void RemoveClientDic(ClientData session) { if (!string.IsNullOrEmpty(session.ChargeBoxId)) { lock (_lockClientDic) { if (clientDic.ContainsKey(session.ChargeBoxId)) { if (clientDic[session.ChargeBoxId].SessionID == session.SessionID) { logger.Debug(String.Format("ChargeBoxId:{0} Remove SessionId:{1} Removed SessionId:{2}", session.ChargeBoxId, session.SessionID, clientDic[session.ChargeBoxId].SessionID)); clientDic.Remove(session.ChargeBoxId); logger.Trace("RemoveClient ContainsKey " + session.ChargeBoxId); } } } } } private void WarmUpLog() { try { using (var main = new MainDBContext()) { main.Machine.Where(x => x.ChargeBoxId == "AAA").FirstOrDefault(); // log.MachineConnectionLog.ToList(); } using (var log = new ConnectionLogDBContext()) { log.MachineConnectionLog.ToList(); } } catch (Exception ex) { logger.Error(ex.ToString()); //Console.WriteLine(ex.ToString()); } } private void WriteMachineLog(ClientData clientData, string data, string messageType, string errorMsg = "", bool isSent = false) { try { if (clientData == null || string.IsNullOrEmpty(data)) return; if (clientData.ChargeBoxId == null) { logger.Fatal(clientData.Path + "]********************session ChargeBoxId null sessionId=" + clientData.SessionID); } using (var db = new ConnectionLogDBContext()) { string sp = "[dbo].[uspInsertMachineConnectionLog] @CreatedOn," + "@ChargeBoxId,@MessageType,@Data,@Msg,@IsSent,@EVSEEndPoint,@Session"; var dd = DateTime.UtcNow; SqlParameter[] parameter = { new SqlParameter("CreatedOn",23){ Value=dd}, new SqlParameter("ChargeBoxId",50){ Value=clientData.ChargeBoxId==null?"unknown":clientData.ChargeBoxId.Replace("'","''")}, new SqlParameter("MessageType",50){ Value=messageType.Replace("'","''")}, new SqlParameter("Data",data.Replace("'","''")), new SqlParameter("Msg",200){ Value=errorMsg.Replace("'","''")}, new SqlParameter("IsSent",1){ Value=isSent}, new SqlParameter("EVSEEndPoint",25){ Value=clientData.RemoteEndPoint==null?"123":clientData.RemoteEndPoint.ToString()}, new SqlParameter("Session",36){ Value=clientData.SessionID==null?"123":clientData.SessionID} }; db.Database.ExecuteSqlCommand(sp, parameter); } } catch (Exception ex) { Console.WriteLine(ex.ToString()); } } } }