|
@@ -35,7 +35,7 @@ using EVCB_OCPP.Packet.Messages.SmartCharging;
|
|
|
using System.Security.Authentication;
|
|
|
using NLog.Fluent;
|
|
|
using System.Diagnostics;
|
|
|
-using Packet20 = EVCB_OCPP.Packet20;
|
|
|
+
|
|
|
|
|
|
namespace EVCB_OCPP.WSServer
|
|
|
{
|
|
@@ -100,7 +100,7 @@ namespace EVCB_OCPP.WSServer
|
|
|
};
|
|
|
private CancellationTokenSource _cts = new CancellationTokenSource();
|
|
|
private CancellationToken _ct;
|
|
|
-
|
|
|
+ private string _ocpp20NetworkSetting = "";
|
|
|
|
|
|
internal ProtalServer()
|
|
|
{
|
|
@@ -134,6 +134,22 @@ namespace EVCB_OCPP.WSServer
|
|
|
Task serverHealthTask = new Task(HealthCheckTrigger, _ct);
|
|
|
serverHealthTask.Start();
|
|
|
|
|
|
+ var ocpp20NetworkSetting = new EVCB_OCPP20.Packet.Messages.SetNetworkProfileRequest()
|
|
|
+ {
|
|
|
+ ConfigurationSlot = 0,
|
|
|
+ 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 = "ws://ocpp.phihong.com.tw:5004",
|
|
|
+ OcppInterface = EVCB_OCPP20.Packet.DataTypes.EnumTypes.OCPPInterfaceEnumType.Wired0
|
|
|
+ }
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ _ocpp20NetworkSetting = JsonConvert.SerializeObject(ocpp20NetworkSetting, Formatting.None);
|
|
|
+
|
|
|
while (true)
|
|
|
{
|
|
|
var input = Console.ReadLine();
|
|
@@ -302,13 +318,13 @@ namespace EVCB_OCPP.WSServer
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+
|
|
|
|
|
|
private void OpenNetwork()
|
|
|
{
|
|
|
|
|
|
//載入OCPP Protocol
|
|
|
- var appServer = new OCPPWSServer(new List<OCPPSubProtocol>() { new OCPPSubProtocol(), new OCPPSubProtocol(" ocpp1.6")});
|
|
|
+ var appServer = new OCPPWSServer(new List<OCPPSubProtocol>() { new OCPPSubProtocol(), new OCPPSubProtocol(" ocpp1.6"), new OCPPSubProtocol("ocpp2.0") });
|
|
|
|
|
|
List<IListenerConfig> llistener = new List<IListenerConfig>();
|
|
|
//System.Net.IPAddress.Any.ToString()
|
|
@@ -373,7 +389,7 @@ namespace EVCB_OCPP.WSServer
|
|
|
{
|
|
|
lock (_lockClientDic)
|
|
|
{
|
|
|
- bool isNotSupported = session.SecWebSocketProtocol.Contains("ocpp1.6") ?false : session.SecWebSocketProtocol.Contains("ocpp2.0") ? false : true;
|
|
|
+ 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));
|
|
@@ -430,10 +446,10 @@ namespace EVCB_OCPP.WSServer
|
|
|
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)
|
|
|
+ if (session.ResetSecurityProfile)
|
|
|
{
|
|
|
logger.Error(string.Format("[{0}] ChargeBoxId:{1} ResetSecurityProfile", DateTime.Now, session.ChargeBoxId));
|
|
|
- RemoveClient(session);
|
|
|
+ RemoveClient(session);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -478,107 +494,59 @@ namespace EVCB_OCPP.WSServer
|
|
|
else
|
|
|
{
|
|
|
|
|
|
- Actions action = Convertor.GetAction(analysisResult.Action);
|
|
|
|
|
|
- if (!session.IsOCPP16 && !(action != Actions.BootNotification || action != Actions.Heartbeat))
|
|
|
- {
|
|
|
- Send(session, "Backend doesn't support this message.", string.Format("{0} {1}", analysisResult.Action, "Error"));
|
|
|
- return;
|
|
|
- }
|
|
|
+
|
|
|
+ //if (session.ISOCPP20 && !(analysisResult.Action != Actions.BootNotification.ToString() || analysisResult.Action != Actions.Heartbeat.ToString()))
|
|
|
+ //{
|
|
|
+ // Send(session, "Backend doesn't support this message.", string.Format("{0} {1}", analysisResult.Action, "Error"));
|
|
|
+ // return;
|
|
|
+ //}
|
|
|
switch (analysisResult.Id)
|
|
|
{
|
|
|
case BasicMessageHandler.TYPENUMBER_CALL:
|
|
|
{
|
|
|
- if (session.IsOCPP16)
|
|
|
+ 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 Actions.Heartbeat:
|
|
|
- {
|
|
|
- var confirm = new Packet20.Messages.HeartbeatResponse() { CurrentTime = DateTime.Now };
|
|
|
- result.Message = confirm;
|
|
|
- result.Success = true;
|
|
|
|
|
|
- string response = BasicMessageHandler.GenerateConfirmationofOCPP20(analysisResult.UUID, (Packet20.Messages.IConfirmation)result.Message);
|
|
|
- Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Response"), result.Exception == null ? string.Empty : result.Exception.ToString());
|
|
|
- }
|
|
|
- break;
|
|
|
- case Actions.BootNotification:
|
|
|
+ case EVCB_OCPP20.Packet.Features.Actions.BootNotification:
|
|
|
{
|
|
|
- Packet20.Messages.BootNotificationRequest _request = (Packet20.Messages.IRequest)analysisResult.Message as Packet20.Messages.BootNotificationRequest;
|
|
|
- int heartbeat_interval = GlobalConfig.GetHEARTBEAT_INTERVAL();
|
|
|
- //using (var db = new MainDBContext())
|
|
|
- //{
|
|
|
- // var _machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault();
|
|
|
- // _machine.ChargeBoxSerialNumber = string.IsNullOrEmpty(_request.chargeBoxSerialNumber) ? string.Empty : _request.chargeBoxSerialNumber;
|
|
|
- // _machine.ChargePointModel = string.IsNullOrEmpty(_request.chargePointModel) ? string.Empty : _request.chargePointModel;
|
|
|
- // _machine.ChargePointVendor = string.IsNullOrEmpty(_request.chargePointVendor) ? string.Empty : _request.chargePointVendor;
|
|
|
- // _machine.FW_CurrentVersion = string.IsNullOrEmpty(_request.firmwareVersion) ? string.Empty : _request.firmwareVersion;
|
|
|
- // _machine.Iccid = string.IsNullOrEmpty(_request.iccid) ? string.Empty : _request.iccid;
|
|
|
- // _machine.Imsi = string.IsNullOrEmpty(_request.imsi) ? string.Empty : _request.imsi;
|
|
|
- // _machine.MeterSerialNumber = string.IsNullOrEmpty(_request.meterSerialNumber) ? string.Empty : _request.meterSerialNumber;
|
|
|
- // _machine.MeterType = string.IsNullOrEmpty(_request.meterType) ? string.Empty : _request.meterType;
|
|
|
-
|
|
|
- // db.SaveChanges();
|
|
|
-
|
|
|
- // var configVaule = db.MachineConfiguration.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.ConfigureName == StandardConfiguration.HeartbeatInterval)
|
|
|
- // .Select(x => x.ConfigureSetting).FirstOrDefault();
|
|
|
-
|
|
|
- // if (configVaule != null)
|
|
|
- // {
|
|
|
- // int.TryParse(configVaule, out heartbeat_interval);
|
|
|
- // }
|
|
|
- //}
|
|
|
- var confirm = new Packet20.Messages.BootNotificationResponse() { CurrentTime = DateTime.Now, Interval = heartbeat_interval, Status = Packet20.DataTypes.EnumTypes.RegistrationStatusEnumType.Accepted };
|
|
|
+ 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.Now, Interval = 180, Status = EVCB_OCPP20.Packet.DataTypes.EnumTypes.RegistrationStatusEnumType.Pending };
|
|
|
|
|
|
result.Message = confirm;
|
|
|
result.Success = true;
|
|
|
|
|
|
- string response = BasicMessageHandler.GenerateConfirmationofOCPP20(analysisResult.UUID, (Packet20.Messages.IConfirmation)result.Message);
|
|
|
+ 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());
|
|
|
|
|
|
- }
|
|
|
- break;
|
|
|
- case Actions.StatusNotification:
|
|
|
- {
|
|
|
- Packet20.Messages.StatusNotificationRequest _request = (Packet20.Messages.IRequest)analysisResult.Message as Packet20.Messages.StatusNotificationRequest;
|
|
|
- // int heartbeat_interval = GlobalConfig.GetHEARTBEAT_INTERVAL();
|
|
|
- //using (var db = new MainDBContext())
|
|
|
- //{
|
|
|
- // var _machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault();
|
|
|
- // _machine.ChargeBoxSerialNumber = string.IsNullOrEmpty(_request.chargeBoxSerialNumber) ? string.Empty : _request.chargeBoxSerialNumber;
|
|
|
- // _machine.ChargePointModel = string.IsNullOrEmpty(_request.chargePointModel) ? string.Empty : _request.chargePointModel;
|
|
|
- // _machine.ChargePointVendor = string.IsNullOrEmpty(_request.chargePointVendor) ? string.Empty : _request.chargePointVendor;
|
|
|
- // _machine.FW_CurrentVersion = string.IsNullOrEmpty(_request.firmwareVersion) ? string.Empty : _request.firmwareVersion;
|
|
|
- // _machine.Iccid = string.IsNullOrEmpty(_request.iccid) ? string.Empty : _request.iccid;
|
|
|
- // _machine.Imsi = string.IsNullOrEmpty(_request.imsi) ? string.Empty : _request.imsi;
|
|
|
- // _machine.MeterSerialNumber = string.IsNullOrEmpty(_request.meterSerialNumber) ? string.Empty : _request.meterSerialNumber;
|
|
|
- // _machine.MeterType = string.IsNullOrEmpty(_request.meterType) ? string.Empty : _request.meterType;
|
|
|
-
|
|
|
- // db.SaveChanges();
|
|
|
-
|
|
|
- // var configVaule = db.MachineConfiguration.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.ConfigureName == StandardConfiguration.HeartbeatInterval)
|
|
|
- // .Select(x => x.ConfigureSetting).FirstOrDefault();
|
|
|
-
|
|
|
- // if (configVaule != null)
|
|
|
- // {
|
|
|
- // int.TryParse(configVaule, out heartbeat_interval);
|
|
|
- // }
|
|
|
- //}
|
|
|
- var confirm = new Packet20.Messages.StatusNotificationResponse() { };
|
|
|
|
|
|
- result.Message = confirm;
|
|
|
- result.Success = true;
|
|
|
+ string changeServerRequest = BasicMessageHandler.GenerateRequestofOCPP20(Guid.NewGuid().ToString(), "SetNetworkProfile", new EVCB_OCPP20.Packet.Messages.SetNetworkProfileRequest()
|
|
|
+ {
|
|
|
+ ConfigurationSlot = 0,
|
|
|
+ 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 = "ws://ocpp.phihong.com.tw:5004",
|
|
|
+ OcppInterface = EVCB_OCPP20.Packet.DataTypes.EnumTypes.OCPPInterfaceEnumType.Wired0
|
|
|
+ }
|
|
|
|
|
|
- string response = BasicMessageHandler.GenerateConfirmationofOCPP20(analysisResult.UUID, (Packet20.Messages.IConfirmation)result.Message);
|
|
|
- Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Response"), result.Exception == null ? string.Empty : result.Exception.ToString());
|
|
|
+ }
|
|
|
+ );
|
|
|
|
|
|
+ Send(session, changeServerRequest, "SetNetworkProfile");
|
|
|
}
|
|
|
break;
|
|
|
default:
|
|
@@ -595,8 +563,82 @@ namespace EVCB_OCPP.WSServer
|
|
|
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= _ocpp20NetworkSetting,
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- ProcessConfirmationMessage(analysisResult, session, action);
|
|
|
}
|
|
|
break;
|
|
|
case BasicMessageHandler.TYPENUMBER_CALLERROR:
|
|
@@ -604,6 +646,7 @@ namespace EVCB_OCPP.WSServer
|
|
|
//只處理 丟出Request 收到Error的訊息
|
|
|
if (analysisResult.Success && analysisResult.Message != null)
|
|
|
{
|
|
|
+ Actions action = Convertor.GetAction(analysisResult.Action);
|
|
|
ProcessErrorMessage(analysisResult, session, action);
|
|
|
}
|
|
|
|
|
@@ -815,6 +858,7 @@ namespace EVCB_OCPP.WSServer
|
|
|
|
|
|
private void ProcessConfirmationMessage(MessageResult analysisResult, ClientData session, Actions action)
|
|
|
{
|
|
|
+
|
|
|
BasicMessageHandler msgAnalyser = new BasicMessageHandler();
|
|
|
if (ReConfirmMessage(analysisResult))
|
|
|
{
|
|
@@ -1003,7 +1047,7 @@ namespace EVCB_OCPP.WSServer
|
|
|
string requestId = Guid.NewGuid().ToString();
|
|
|
// using (var db = new MainDBContext())
|
|
|
|
|
|
- if (session.IsCheckIn && session.IsOCPP16)
|
|
|
+ if (session.IsCheckIn && !session.ISOCPP20)
|
|
|
{
|
|
|
|
|
|
var _request = new TriggerMessageRequest()
|
|
@@ -1126,7 +1170,7 @@ namespace EVCB_OCPP.WSServer
|
|
|
{
|
|
|
Console.WriteLine(string.Format("charger_SN:{0} startDt:{1} CreatedOn:{2}", charger_SN, startDt.ToString("yyyy/MM/dd HH:mm:ss"), DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
|
|
|
|
|
- if (session.IsCheckIn && session.IsOCPP16)
|
|
|
+ if (session.IsCheckIn && !session.ISOCPP20)
|
|
|
{
|
|
|
var cmdList = commandList.Where(c => c.ChargeBoxId == charger_SN).ToList();
|
|
|
|