|
@@ -0,0 +1,2171 @@
|
|
|
+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
|
|
|
+ {
|
|
|
+ static private ILogger logger = NLog.LogManager.GetCurrentClassLogger();
|
|
|
+ private OuterHttpClient httpClient = new OuterHttpClient();
|
|
|
+ private DateTime lastcheckdt = DateTime.UtcNow.AddSeconds(-20);
|
|
|
+ private Dictionary<string, ClientData> clientDic = new Dictionary<string, ClientData>();
|
|
|
+ private readonly Object _lockClientDic = new object();
|
|
|
+ private readonly Object _lockConfirmPacketList = new object();
|
|
|
+ private ProfileHandler profileHandler = new ProfileHandler();
|
|
|
+ private List<NeedConfirmMessage> needConfirmPacketList = new List<NeedConfirmMessage>();
|
|
|
+ private DateTime checkUpdateDt = DateTime.UtcNow;
|
|
|
+ private DateTime _CheckFeeDt = DateTime.UtcNow;
|
|
|
+ private DateTime _CheckWeatherDt = DateTime.UtcNow;
|
|
|
+ private LoadingBalanceService _loadingBalanceService = new LoadingBalanceService();
|
|
|
+ private Dictionary<string, TCCWeatherDto> TCCStationDic = new Dictionary<string, TCCWeatherDto>();
|
|
|
+
|
|
|
+ private List<string> needConfirmActions = new List<string>()
|
|
|
+ {
|
|
|
+ "GetConfiguration",
|
|
|
+ "ChangeConfiguration",
|
|
|
+ "RemoteStartTransaction",
|
|
|
+ "RemoteStopTransaction",
|
|
|
+ "ChangeAvailability",
|
|
|
+ "ClearCache",
|
|
|
+ "DataTransfer",
|
|
|
+ "Reset",
|
|
|
+ "UnlockConnector",
|
|
|
+ "TriggerMessage",
|
|
|
+ "GetDiagnostics",
|
|
|
+ "UpdateFirmware",
|
|
|
+ "GetLocalListVersion",
|
|
|
+ "SendLocalList",
|
|
|
+ "SetChargingProfile",
|
|
|
+ "ClearChargingProfile",
|
|
|
+ "GetCompositeSchedule",
|
|
|
+ "ReserveNow",
|
|
|
+ "CancelReservation",
|
|
|
+ "ExtendedTriggerMessage"
|
|
|
+ };
|
|
|
+ private List<Profile> profiles = new List<Profile>()
|
|
|
+ {
|
|
|
+ new CoreProfile(),
|
|
|
+ new FirmwareManagementProfile(),
|
|
|
+ new ReservationProfile(),
|
|
|
+ new RemoteTriggerProfile(),
|
|
|
+ new SmartChargingProfile(),
|
|
|
+ new LocalAuthListManagementProfile(),
|
|
|
+ new SecurityProfile(),
|
|
|
+ };
|
|
|
+ private CancellationTokenSource _cts = new CancellationTokenSource();
|
|
|
+ private CancellationToken _ct;
|
|
|
+ private string _ocpp20NetworkSetting = "";
|
|
|
+
|
|
|
+ internal ProtalServer()
|
|
|
+ {
|
|
|
+ _ct = _cts.Token;
|
|
|
+ WarmUpLog();
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ internal void Start()
|
|
|
+ {
|
|
|
+
|
|
|
+ if (!GlobalConfig.LoadAPPConfig())
|
|
|
+ {
|
|
|
+ Console.WriteLine("Please check App.Config setting .");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ //ReadTCCSetting();
|
|
|
+ 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 serverWeatherNotificationTask = new Task(ServerWeatherNotificationTrigger, _ct);
|
|
|
+ serverWeatherNotificationTask.Start();
|
|
|
+
|
|
|
+ Task serverBeatTask = new Task(HeartBeatCheckTrigger, _ct);
|
|
|
+ serverBeatTask.Start();
|
|
|
+
|
|
|
+ Task serverHealthTask = new Task(HealthCheckTrigger, _ct);
|
|
|
+ serverHealthTask.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<string, ClientData> _copyClientDic = null;
|
|
|
+ lock (_lockClientDic)
|
|
|
+ {
|
|
|
+ _copyClientDic = new Dictionary<string, ClientData>(clientDic);
|
|
|
+
|
|
|
+ }
|
|
|
+ var list = _copyClientDic.Select(c => c.Value).ToList();
|
|
|
+ var locations = _copyClientDic.Where(x => !string.IsNullOrEmpty(x.Value.StationLocation)).Distinct().Select(x => x.Value.StationLocation).ToList();
|
|
|
+ int i = 1;
|
|
|
+ foreach (var c in list)
|
|
|
+ {
|
|
|
+ Console.WriteLine(i + ":" + c.ChargeBoxId + " " + c.SessionID);
|
|
|
+ i++;
|
|
|
+ }
|
|
|
+
|
|
|
+ foreach (var c in TCCStationDic)
|
|
|
+ {
|
|
|
+ Console.WriteLine(i + ":" + c.Key + "-" + c.Value.Temperature + "/" + c.Value.WeatherID);
|
|
|
+ i++;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case "lcn":
|
|
|
+ {
|
|
|
+ Console.WriteLine("Command List Customer Name");
|
|
|
+ Dictionary<string, ClientData> _copyClientDic = null;
|
|
|
+ lock (_lockClientDic)
|
|
|
+ {
|
|
|
+ _copyClientDic = new Dictionary<string, ClientData>(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 CheckVersion(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.DataTransfer.ToString(),
|
|
|
+ OutRequest = JsonConvert.SerializeObject(
|
|
|
+ new DataTransferRequest()
|
|
|
+ {
|
|
|
+ messageId = "ID_FirmwareVersion",
|
|
|
+ vendorId = "Phihong Technology"
|
|
|
+
|
|
|
+ },
|
|
|
+ new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
|
|
|
+ SerialNo = Guid.NewGuid().ToString(),
|
|
|
+ InMessage = string.Empty
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ db.SaveChanges();
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ 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<string>()
|
|
|
+
|
|
|
+ },
|
|
|
+ new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
|
|
|
+ SerialNo = Guid.NewGuid().ToString(),
|
|
|
+ InMessage = string.Empty
|
|
|
+
|
|
|
+ }); ;
|
|
|
+
|
|
|
+ db.SaveChanges();
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ #region 台泥
|
|
|
+
|
|
|
+
|
|
|
+ private void ReadTCCSetting()
|
|
|
+ {
|
|
|
+ using (var db = new MainDBContext())
|
|
|
+ {
|
|
|
+ var info = db.Customer.Where(x => x.Id == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8")).Select(x => new { x.ApiUrl, x.ApiKey }).FirstOrDefault();
|
|
|
+ GlobalConfig.TCC_API_URL = info.ApiUrl;
|
|
|
+ GlobalConfig.TCC_SALTKEY = info.ApiKey;
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ async private Task<TCCStationInfoDto> GetStationInfo(string machineId)
|
|
|
+ {
|
|
|
+ TCCStationInfoDto stationInfo = null;
|
|
|
+ if (string.IsNullOrEmpty(machineId)) return stationInfo;
|
|
|
+ using (SqlConnection conn = new SqlConnection(webConnectionString))
|
|
|
+ {
|
|
|
+ var parameters = new DynamicParameters();
|
|
|
+ parameters.Add("@MachineId", machineId, DbType.String, ParameterDirection.Input);
|
|
|
+ string sql = " SELECT CAST([Latitude] as DECIMAL(5,2)) Lat,CAST([Longitude] as DECIMAL(5, 2)) Long ,SUBSTRING([Address],1,3) as zipcode FROM[StationMachine] left join [dbo].[Station]" +
|
|
|
+ " on[StationMachine].StationId = Station.[Id] where StationMachine.MachineId=@MachineId; ";
|
|
|
+
|
|
|
+ var result = await conn.QueryAsync<TCCStationInfoDto>(sql, parameters);
|
|
|
+ stationInfo = result.FirstOrDefault();
|
|
|
+ }
|
|
|
+
|
|
|
+ return stationInfo;
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ private void OpenNetwork()
|
|
|
+ {
|
|
|
+
|
|
|
+ //載入OCPP Protocol
|
|
|
+ var appServer = new OCPPWSServer(new List<OCPPSubProtocol>() { new OCPPSubProtocol(), new OCPPSubProtocol(" ocpp1.6"), new OCPPSubProtocol("ocpp2.0") });
|
|
|
+
|
|
|
+ List<IListenerConfig> llistener = new List<IListenerConfig>();
|
|
|
+
|
|
|
+ llistener.Add(new ListenerConfig { Ip = System.Net.IPAddress.Any.ToString(), Port = Convert.ToInt32(GlobalConfig.GetWS_Port()), Backlog = 100, Security = "None" });
|
|
|
+ llistener.Add(new ListenerConfig { Ip = System.Net.IPAddress.Any.ToString(), Port = Convert.ToInt32(GlobalConfig.GetWSS_Port()), Backlog = 100, Security = SslProtocols.Tls12.ToString() });
|
|
|
+
|
|
|
+ var config = ConfigurationManager.GetSection("superSocket") as IConfigurationSource;
|
|
|
+ ICertificateConfig Certificate = config.Servers.ElementAt(0).Certificate;
|
|
|
+ IEnumerable<IListenerConfig> listeners = llistener;
|
|
|
+
|
|
|
+ //設定server config
|
|
|
+ var serverConfig = new ServerConfig
|
|
|
+ {
|
|
|
+ //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<ClientData, String>(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<EVCB_OCPP20.Packet.DataTypes.SetVariableDataType>()
|
|
|
+ {
|
|
|
+ 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<int>(){ 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)
|
|
|
+ {
|
|
|
+
|
|
|
+ CheckVersion(session.ChargeBoxId);
|
|
|
+ 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();
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (session.CustomerId == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8"))
|
|
|
+ {
|
|
|
+
|
|
|
+ var stationInfo = await GetStationInfo(session.MachineId);
|
|
|
+ if (stationInfo != null)
|
|
|
+ {
|
|
|
+ session.StationLocation = string.Format("{0},{1}", stationInfo.Lat, stationInfo.Long);
|
|
|
+ session.StationName = stationInfo.ZipCode;
|
|
|
+ }
|
|
|
+ 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_Station_Location",
|
|
|
+ vendorId = "Phihong Technology",
|
|
|
+ data = JsonConvert.SerializeObject(new { stationName = session.StationName })
|
|
|
+
|
|
|
+ },
|
|
|
+ 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 = "TimeOffset",
|
|
|
+ value = "+08:00"
|
|
|
+
|
|
|
+ },
|
|
|
+ new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
|
|
|
+ SerialNo = Guid.NewGuid().ToString(),
|
|
|
+ InMessage = string.Empty
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ if (!TCCStationDic.ContainsKey(session.StationLocation))
|
|
|
+ {
|
|
|
+
|
|
|
+ _CheckWeatherDt = DateTime.UtcNow.AddDays(-1);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+
|
|
|
+ db.ServerMessage.Add(new ServerMessage()
|
|
|
+ {
|
|
|
+ ChargeBoxId = session.ChargeBoxId,
|
|
|
+ CreatedBy = "Server",
|
|
|
+ CreatedOn = DateTime.UtcNow,
|
|
|
+ OutAction = Actions.DataTransfer.ToString(),
|
|
|
+ OutRequest = JsonConvert.SerializeObject(
|
|
|
+ new DataTransferRequest()
|
|
|
+ {
|
|
|
+ messageId = "ID_Weather_Info",
|
|
|
+ vendorId = "Phihong Technology",
|
|
|
+ data = JsonConvert.SerializeObject(
|
|
|
+ new
|
|
|
+ {
|
|
|
+ weatherId = TCCStationDic[session.StationLocation].WeatherID,
|
|
|
+ Temperature = TCCStationDic[session.StationLocation].Temperature
|
|
|
+ })
|
|
|
+ },
|
|
|
+ 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);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ #region 台泥
|
|
|
+ if (action == Actions.StartTransaction && session.CustomerId == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8") && replyResult.Message is StartTransactionConfirmation)
|
|
|
+ {
|
|
|
+
|
|
|
+ StartTransactionConfirmation confirm = (StartTransactionConfirmation)replyResult.Message;
|
|
|
+ StartTransactionRequest request = (StartTransactionRequest)analysisResult.Message;
|
|
|
+ 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_GetTxUserInfo",
|
|
|
+ vendorId = "Phihong Technology",
|
|
|
+ data = JsonConvert.SerializeObject(new { txId = confirm.transactionId, ConnectorId = request.connectorId })
|
|
|
+ },
|
|
|
+ new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
|
|
|
+ SerialNo = Guid.NewGuid().ToString(),
|
|
|
+ InMessage = string.Empty
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ db.SaveChanges();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ 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
|
|
|
+ }
|
|
|
+ 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 = _loadingBalanceService.GetSettingPower(stationId, session.MachineId);
|
|
|
+ if (_powerDic != null)
|
|
|
+ {
|
|
|
+ foreach (var kv in _powerDic)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ string chargeBoxId = string.Empty;
|
|
|
+ //set profile
|
|
|
+ lock (_lockClientDic)
|
|
|
+ {
|
|
|
+ chargeBoxId = clientDic.Where(x => x.Value.MachineId == kv.Key).Select(x => x.Value.ChargeBoxId).FirstOrDefault();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (chargeBoxId != null && kv.Value.HasValue)
|
|
|
+ {
|
|
|
+ profileHandler.SetChargingProfile(chargeBoxId, 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);
|
|
|
+ if (_loadingBalanceService.IsNeedtoCancelSetting(stationId, session.MachineId, session.ChargeBoxId))
|
|
|
+ {
|
|
|
+ //Clear current profile
|
|
|
+ profileHandler.ClearChargingProfile(session.ChargeBoxId);
|
|
|
+
|
|
|
+ var _powerDic = _loadingBalanceService.GetRerangeSettingPower(stationId);
|
|
|
+ if (_powerDic != null)
|
|
|
+ {
|
|
|
+ foreach (var kv in _powerDic)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ string chargeBoxId = string.Empty;
|
|
|
+ //set profile
|
|
|
+ lock (_lockClientDic)
|
|
|
+ {
|
|
|
+ chargeBoxId = clientDic.Where(x => x.Value.MachineId == kv.Key).Select(x => x.Value.ChargeBoxId).FirstOrDefault();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (chargeBoxId != null && kv.Value.HasValue)
|
|
|
+ {
|
|
|
+ profileHandler.SetChargingProfile(chargeBoxId, 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 = 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 ServerUpdateTrigger()
|
|
|
+ {
|
|
|
+ for (; ; )
|
|
|
+ {
|
|
|
+ if (_ct.IsCancellationRequested)
|
|
|
+ {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ var min_Interval = (DateTime.UtcNow - checkUpdateDt).TotalMinutes;
|
|
|
+ if (min_Interval > 3)
|
|
|
+ {
|
|
|
+ BasicMessageHandler msgAnalyser = new BasicMessageHandler();
|
|
|
+ Dictionary<string, ClientData> _copyClientDic = null;
|
|
|
+ lock (_lockClientDic)
|
|
|
+ {
|
|
|
+ _copyClientDic = new Dictionary<string, ClientData>(clientDic);
|
|
|
+
|
|
|
+ }
|
|
|
+ checkUpdateDt = DateTime.UtcNow;
|
|
|
+ using (var db = new MainDBContext())
|
|
|
+ {
|
|
|
+ //var needUpdateChargers = db.Machine.Where(x => x.FW_AssignedMachineVersionId.HasValue == true &&
|
|
|
+ // x.FW_AssignedMachineVersionId != x.FW_VersionReport && x.Online == true)
|
|
|
+ // .Select(x => new { x.Id, x.ChargeBoxId, x.FW_AssignedMachineVersionId }).ToList();
|
|
|
+
|
|
|
+ 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();
|
|
|
+ // using (var db = new MainDBContext())
|
|
|
+
|
|
|
+ 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);
|
|
|
+ // Thread.CurrentThread.Join(1000);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ string webConnectionString = ConfigurationManager.ConnectionStrings["WebDBContext"].ConnectionString;
|
|
|
+
|
|
|
+ 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<string, ClientData> _copyClientDic = null;
|
|
|
+ lock (_lockClientDic)
|
|
|
+ {
|
|
|
+ _copyClientDic = new Dictionary<string, ClientData>(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())
|
|
|
+ {
|
|
|
+ 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();
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ 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 ServerWeatherNotificationTrigger()
|
|
|
+ {
|
|
|
+ for (; ; )
|
|
|
+ {
|
|
|
+ if (_ct.IsCancellationRequested)
|
|
|
+ {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ var min_Interval = (DateTime.UtcNow - _CheckWeatherDt).TotalMinutes;
|
|
|
+
|
|
|
+ if (min_Interval > 30)
|
|
|
+ {
|
|
|
+ // Console.WriteLine("in...............ServerWeatherNotificationTrigger");
|
|
|
+ BasicMessageHandler msgAnalyser = new BasicMessageHandler();
|
|
|
+ Dictionary<string, ClientData> _copyClientDic = null;
|
|
|
+ lock (_lockClientDic)
|
|
|
+ {
|
|
|
+ _copyClientDic = new Dictionary<string, ClientData>(clientDic);
|
|
|
+
|
|
|
+ }
|
|
|
+ _CheckWeatherDt = DateTime.UtcNow;
|
|
|
+
|
|
|
+ var locations = _copyClientDic.Where(x => !string.IsNullOrEmpty(x.Value.StationLocation)).Distinct().Select(x => x.Value.StationLocation).ToList();
|
|
|
+
|
|
|
+ // Console.WriteLine("in...............ServerWeatherNotificationTrigger");
|
|
|
+ foreach (var location in locations)
|
|
|
+ {
|
|
|
+
|
|
|
+ try
|
|
|
+ { //query weather
|
|
|
+ var httpResult = await httpClient.GetWeather("https://api.weatherapi.com/v1/current.json?key=874346abc0874e69a9423510222201&q=" + location, null, null);
|
|
|
+
|
|
|
+ string temp = "17";
|
|
|
+ string weather_code = "1183";
|
|
|
+ if (httpResult.Status == System.Net.HttpStatusCode.OK)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ var jsonResult = JsonConvert.DeserializeObject(httpResult.Response) as JObject;
|
|
|
+ temp = jsonResult["current"]["temp_c"].ToString();
|
|
|
+ weather_code = jsonResult["current"]["condition"]["code"].ToString();
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ ;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ #region 台泥氣象Mapping
|
|
|
+ switch (weather_code)
|
|
|
+ {
|
|
|
+ case "1000":
|
|
|
+ weather_code = "1";
|
|
|
+ break;
|
|
|
+ case "1003":
|
|
|
+ case "1006":
|
|
|
+ case "1009":
|
|
|
+ weather_code = "2";
|
|
|
+ break;
|
|
|
+ case "1063":
|
|
|
+ case "1072":
|
|
|
+ case "1150":
|
|
|
+ case "1153":
|
|
|
+ case "1168":
|
|
|
+ case "1171":
|
|
|
+ case "1180":
|
|
|
+ case "1183":
|
|
|
+ case "1186":
|
|
|
+ case "1189":
|
|
|
+ case "1192":
|
|
|
+ case "1195":
|
|
|
+ case "1198":
|
|
|
+ case "1201":
|
|
|
+ case "1237":
|
|
|
+ case "1240":
|
|
|
+ case "1243":
|
|
|
+ case "1246":
|
|
|
+ case "1261":
|
|
|
+ case "1264":
|
|
|
+ weather_code = "3";
|
|
|
+ break;
|
|
|
+ case "1087":
|
|
|
+ case "1273":
|
|
|
+ case "1276":
|
|
|
+ case "1279":
|
|
|
+ case "1282":
|
|
|
+ weather_code = "4";
|
|
|
+ break;
|
|
|
+ case "1066":
|
|
|
+ case "1069":
|
|
|
+ case "1114":
|
|
|
+ case "1117":
|
|
|
+ case "1204":
|
|
|
+ case "1207":
|
|
|
+ case "1210":
|
|
|
+ case "1213":
|
|
|
+ case "1216":
|
|
|
+ case "1219":
|
|
|
+ case "1222":
|
|
|
+ case "1225":
|
|
|
+ case "1249":
|
|
|
+ case "1252":
|
|
|
+ case "1255":
|
|
|
+ case "1258":
|
|
|
+ weather_code = "5";
|
|
|
+ break;
|
|
|
+ case "1030":
|
|
|
+ case "1135":
|
|
|
+ case "1147":
|
|
|
+ weather_code = "2";
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ weather_code = "2";
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+
|
|
|
+
|
|
|
+ if (TCCStationDic.ContainsKey(location))
|
|
|
+ {
|
|
|
+ TCCStationDic[location].Temperature = (int)double.Parse(temp);
|
|
|
+ TCCStationDic[location].WeatherID = int.Parse(weather_code);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ TCCStationDic.Add(location, new TCCWeatherDto() { WeatherID = int.Parse(weather_code), Temperature = (int)double.Parse(temp) });
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ logger.Error(string.Format("ServerWeatherNotificationTrigger ChargeBoxId:{0} Ex:{1}", location, ex.ToString()));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ var clients = _copyClientDic.Where(x => x.Value.CustomerId == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8")).
|
|
|
+ Select(x => new { ChargeBoxId = x.Value.ChargeBoxId, StationLocation = x.Value.StationLocation }).ToList();
|
|
|
+
|
|
|
+ using (var db = new MainDBContext())
|
|
|
+ {
|
|
|
+
|
|
|
+ foreach (var client in clients)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (string.IsNullOrEmpty(client.StationLocation))
|
|
|
+ {
|
|
|
+ Console.WriteLine(client.StationLocation + " is empty");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (TCCStationDic.ContainsKey(client.StationLocation))
|
|
|
+ {
|
|
|
+ db.ServerMessage.Add(new ServerMessage()
|
|
|
+ {
|
|
|
+ ChargeBoxId = client.ChargeBoxId,
|
|
|
+ CreatedBy = "Server",
|
|
|
+ CreatedOn = DateTime.UtcNow,
|
|
|
+ OutAction = Actions.DataTransfer.ToString(),
|
|
|
+ OutRequest = JsonConvert.SerializeObject(
|
|
|
+ new DataTransferRequest()
|
|
|
+ {
|
|
|
+ messageId = "ID_Weather_Info",
|
|
|
+ vendorId = "Phihong Technology",
|
|
|
+ data = JsonConvert.SerializeObject(
|
|
|
+ new
|
|
|
+ {
|
|
|
+ weatherId = TCCStationDic[client.StationLocation].WeatherID,
|
|
|
+ Temperature = TCCStationDic[client.StationLocation].Temperature
|
|
|
+ })
|
|
|
+ },
|
|
|
+ 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("ServerWeatherNotificationTrigger ChargeBoxId:{0} Ex:{1}", client.ChargeBoxId, ex.ToString()));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ await Task.Delay(1000);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ 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<string, ClientData> _copyClientDic = null;
|
|
|
+ lock (_lockClientDic)
|
|
|
+ {
|
|
|
+ _copyClientDic = new Dictionary<string, ClientData>(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 Task<string> SetDefaultFee(ClientData client)
|
|
|
+ {
|
|
|
+ string displayPriceText = string.Empty;
|
|
|
+ string charingPriceText = string.Empty;
|
|
|
+
|
|
|
+ if (string.IsNullOrEmpty(client.ChargeBoxId)) return displayPriceText;
|
|
|
+
|
|
|
+ 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<StationFee>(displayPricestrSql, parameters);
|
|
|
+ if (result.Count() == 0)
|
|
|
+ {
|
|
|
+ return string.Empty;
|
|
|
+ }
|
|
|
+ var stationPrice = result.First();
|
|
|
+
|
|
|
+ if (stationPrice.BillingMethod == 1)
|
|
|
+ {
|
|
|
+ var chargingPriceResult = await conn.QueryAsync<ChargingPrice>(strSql, parameters);
|
|
|
+ client.ChargingPrices = chargingPriceResult.ToList();
|
|
|
+ if (string.IsNullOrEmpty(client.ChargingPrices[0].StartTime))
|
|
|
+ {
|
|
|
+ client.ChargingPrices = new List<ChargingPrice>();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ displayPriceText = stationPrice.FeeName;
|
|
|
+ client.BillingMethod = stationPrice.BillingMethod;
|
|
|
+ client.Currency = stationPrice.Currency;
|
|
|
+ client.ChargingFeebyHour = stationPrice.ChargingFeebyHour;
|
|
|
+ client.ParkingFee = stationPrice.ParkingFee;
|
|
|
+ client.IsBilling = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return displayPriceText;
|
|
|
+ }
|
|
|
+
|
|
|
+ async private void HealthCheckTrigger()
|
|
|
+ {
|
|
|
+ for (; ; )
|
|
|
+ {
|
|
|
+ if (_ct.IsCancellationRequested)
|
|
|
+ {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ Dictionary<string, ClientData> _copyClientDic = null;
|
|
|
+ lock (_lockClientDic)
|
|
|
+ {
|
|
|
+ _copyClientDic = new Dictionary<string, ClientData>(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<NeedConfirmMessage> GetResendMessage()
|
|
|
+ {
|
|
|
+ List<NeedConfirmMessage> sendMessages = new List<NeedConfirmMessage>();
|
|
|
+ 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<ClientData, String>(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 log = new ConnectionLogDBContext())
|
|
|
+ {
|
|
|
+ log.MachineConnectionLog.ToList();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ 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",dd),
|
|
|
+ new SqlParameter("ChargeBoxId",clientData.ChargeBoxId==null?"unknown":clientData.ChargeBoxId.Replace("'","''")),
|
|
|
+ new SqlParameter("MessageType",messageType.Replace("'","''")),
|
|
|
+ new SqlParameter("Data",data.Replace("'","''")),
|
|
|
+ new SqlParameter("Msg",errorMsg.Replace("'","''")),
|
|
|
+ new SqlParameter("IsSent",isSent),
|
|
|
+ new SqlParameter("EVSEEndPoint",clientData.RemoteEndPoint==null?"123":clientData.RemoteEndPoint.ToString()),
|
|
|
+ new SqlParameter("Session",clientData.SessionID==null?"123":clientData.SessionID)
|
|
|
+ };
|
|
|
+
|
|
|
+ db.Database.ExecuteSqlCommand(sp, parameter);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ Console.WriteLine(ex.ToString());
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|