Browse Source

Merge branch 'Docker' into Docker_VID

Robert 10 tháng trước cách đây
mục cha
commit
696e8a6bb1

BIN
EVCB_OCPP.WSServer/DLL/EVCB_OCPP.Domain.dll


+ 2 - 1
EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj

@@ -40,7 +40,7 @@
     </BootstrapperPackage>
   </ItemGroup>
   <ItemGroup>
-    <PackageReference Include="Azure.Identity" Version="1.10.4" />
+    <PackageReference Include="Azure.Identity" Version="1.11.2" />
     <PackageReference Include="Dapper" Version="2.0.143" />
     <PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.12" />
     <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.12" />
@@ -57,6 +57,7 @@
     <PackageReference Include="Polly" Version="7.2.4" />
     <PackageReference Include="Quartz.Extensions.Hosting" Version="3.7.0" />
     <PackageReference Include="RestSharp" Version="110.2.0" />
+    <PackageReference Include="System.Configuration.ConfigurationManager" Version="8.0.0" />
     <PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
     <PackageReference Include="System.Security.Cryptography.Pkcs" Version="6.0.3" />
     <PackageReference Include="System.ServiceModel.Federation" Version="6.0.0" />

+ 23 - 8
EVCB_OCPP.WSServer/Message/CoreProfileHandler.cs

@@ -314,6 +314,21 @@ internal partial class ProfileHandler
 								VendorId = string.IsNullOrEmpty(_request.vendorId) ? string.Empty : _request.vendorId,
 								VendorErrorCode = string.IsNullOrEmpty(_request.vendorErrorCode) ? string.Empty : _request.vendorErrorCode
 							});
+
+							if (preStatus == (int)ChargePointStatus.Faulted)
+							{
+								if (_request.status != ChargePointStatus.Faulted ||
+									(_oldStatus.ChargePointErrorCodeId != (int)_request.errorCode && _oldStatus.VendorErrorCode != _request.vendorErrorCode))
+								{									
+									await mainDbService.FillupFinishedTimetoMachineError(
+										ConnectorId: (byte)_request.connectorId,
+										FinishedOn: _request.timestamp.HasValue ? _request.timestamp.Value : DateTime.UtcNow,									
+										ChargeBoxId: session.ChargeBoxId,
+										PreviousErrorOn: _oldStatus.CreatedOn
+										);
+								}
+
+							}
 						}
 
 						s2 = statusNotificationTimer.ElapsedMilliseconds;
@@ -368,7 +383,7 @@ internal partial class ProfileHandler
 						result.Message = confirm;
 						result.Success = true;
 
-						statusNotificationTimer.Stop();
+						statusNotificationTimer.Stop();						
 						if (statusNotificationTimer.ElapsedMilliseconds / 1000 > 1)
 						{
 							logger.LogCritical(string.Format("StatusNotification took {0}/{1}/{2}/{3}/{4}", s1, s2, s3, s4, s5));
@@ -435,9 +450,9 @@ internal partial class ProfileHandler
 							{
 								foreach (var sampleVaule in item.sampledValue)
 								{
-                                    if (sampleVaule.format == ValueFormat.SignedData) continue;
+									if (sampleVaule.format == ValueFormat.SignedData) continue;
 
-                                    decimal value = Convert.ToDecimal(sampleVaule.value);
+									decimal value = Convert.ToDecimal(sampleVaule.value);
 									datas.Add(new InsertMeterValueParam(
 										chargeBoxId: session.ChargeBoxId
 										, connectorId: (byte)_request.connectorId
@@ -536,7 +551,7 @@ internal partial class ProfileHandler
 
 						if (_request.idTag != "Backend")
 						{
-							var authorization_result = await businessService.Authorize(session.ChargeBoxId, _request.idTag);
+							var authorization_result = await businessService.Authorize(session.ChargeBoxId, _request.idTag, source: Actions.StartTransaction.ToString());
 							_idTagInfo = authorization_result.IdTagInfo;
 							t1 = timer.ElapsedMilliseconds;
 
@@ -647,8 +662,8 @@ internal partial class ProfileHandler
 					{
 						StopTransactionRequest _request = request as StopTransactionRequest;
 
-						//遠傳太久以前的停止充電 直接拒絕 避免電樁持續重送~~~~~~~
-						if (_request.timestamp < new DateTime(2021, 11, 1))
+						//遠傳太久以前的停止充電 或 電樁上傳TransactionId=0 直接拒絕 避免電樁持續重送~~~~~~~
+						if (_request.timestamp < new DateTime(2021, 11, 1) || _request.transactionId == 0)
 						{
 							var confirm = new StopTransactionConfirmation()
 							{
@@ -683,7 +698,7 @@ internal partial class ProfileHandler
 									expiryDate = utcNow.AddDays(1),
 									status = AuthorizationStatus.Accepted
 								} :
-								(await businessService.Authorize(session.ChargeBoxId, _request.idTag, transaction?.ConnectorId)).IdTagInfo
+								(await businessService.Authorize(session.ChargeBoxId, _request.idTag, transaction?.ConnectorId, source: Actions.StopTransaction.ToString())).IdTagInfo
 							);
 						getTagInfoTime = stopTrasactionTimer.ElapsedMilliseconds;
 
@@ -877,7 +892,7 @@ internal partial class ProfileHandler
 						};
 						if (_request.idTag != "Backend")
 						{
-							var authorization_result = await businessService.Authorize(session.ChargeBoxId, _request.idTag);
+							var authorization_result = await businessService.Authorize(session.ChargeBoxId, _request.idTag, source: Actions.Authorize.ToString());
 							confirm.idTagInfo = authorization_result.IdTagInfo;
 
 							if (confirm.idTagInfo.status == AuthorizationStatus.Accepted && authorization_result.ChargePointFee != null)

+ 0 - 3
EVCB_OCPP.WSServer/Program.cs

@@ -77,10 +77,7 @@ namespace EVCB_OCPP.WSServer
             app.UseHeaderRecordService();
             app.UseOcppWsService();
             app.MapApiServce();
-            app.Urls.Add("http://*:80");
-
             app.InitStationConfigService();
-            //app.InitVendorIdReplaceService();
             app.Run();
             //host.Run();
         }

+ 1 - 1
EVCB_OCPP.WSServer/Service/BusinessServiceFactory.cs

@@ -14,7 +14,7 @@ namespace EVCB_OCPP.WSServer.Service;
 
 public interface IBusinessService
 {
-    Task<IdTokenInfo> Authorize(string chargeBoxId, string idTag, int? connectorId = null);
+    Task<IdTokenInfo> Authorize(string chargeBoxId, string idTag, int? connectorId = null, string source = null);
 
     Task NotifyFaultStatus(ErrorDetails details);
 

+ 26 - 6
EVCB_OCPP.WSServer/Service/DbService/MainDbService.cs

@@ -11,13 +11,10 @@ using EVCB_OCPP.Packet.Messages.Reservation;
 using EVCB_OCPP.Packet.Messages.Security;
 using EVCB_OCPP.Packet.Messages.SmartCharging;
 using EVCB_OCPP.WSServer.Helper;
-using EVCB_OCPP.WSServer.Message;
-using Microsoft.AspNetCore.Connections;
 using Microsoft.Data.SqlClient;
 using Microsoft.EntityFrameworkCore;
 using Microsoft.Extensions.Caching.Memory;
 using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.Hosting;
 using Microsoft.Extensions.Logging;
 using Newtonsoft.Json;
 using OCPPPackage.Profiles;
@@ -41,7 +38,9 @@ public interface IMainDbService
     Task<string> AddServerMessage(ServerMessage message);
     Task<string> AddServerMessage(string ChargeBoxId, string OutAction, object OutRequest, string CreatedBy = "", DateTime? CreatedOn = null, string SerialNo = "", string InMessage = "");
     ValueTask AddMachineError(byte ConnectorId, DateTime CreatedOn, int Status, string ChargeBoxId, int ErrorCodeId, string ErrorInfo, int PreStatus, string VendorErrorCode, string VendorId);
-    ValueTask<Customer> GetCustomer(string id, CancellationToken token = default);
+	ValueTask FillupFinishedTimetoMachineError(byte ConnectorId, DateTime FinishedOn, string ChargeBoxId, DateTime PreviousErrorOn);
+
+	ValueTask<Customer> GetCustomer(string id, CancellationToken token = default);
     ValueTask<Customer> GetCustomer(Guid id, CancellationToken token = default);
     Task<Guid> GetCustomerIdByChargeBoxId(string chargeboxId);
     Task<int?> TryGetDuplicatedTransactionId(string chargeBoxId, Guid customerId, int connectorId, DateTime timestamp);
@@ -239,7 +238,13 @@ public class MainDbService : IMainDbService
         return AddMachineErrorDapper(ConnectorId, CreatedOn, Status, ChargeBoxId, ErrorCodeId, ErrorInfo, PreStatus, VendorErrorCode, VendorId);
     }
 
-    public async Task<string> AddServerMessage(string ChargeBoxId, string OutAction, object OutRequest, string CreatedBy, DateTime? CreatedOn = null, string SerialNo = "", string InMessage = "")
+	public ValueTask FillupFinishedTimetoMachineError(byte ConnectorId, DateTime FinishedOn, string ChargeBoxId, DateTime PreviousErrorOn)
+	{
+		
+		return AddFinishedTimetoMachineErrorDapper(ConnectorId, FinishedOn, ChargeBoxId, PreviousErrorOn);
+	}
+
+	public async Task<string> AddServerMessage(string ChargeBoxId, string OutAction, object OutRequest, string CreatedBy, DateTime? CreatedOn = null, string SerialNo = "", string InMessage = "")
     {
         if (string.IsNullOrEmpty(CreatedBy))
         {
@@ -833,7 +838,22 @@ public class MainDbService : IMainDbService
             """, parameters);
     }
 
-    private async Task BundleUpdateConnectorStatus(IEnumerable<StatusNotificationParam> statusNotifications)
+	private async ValueTask AddFinishedTimetoMachineErrorDapper(byte connectorId, DateTime finishedTime, string chargeBoxId, DateTime previousErrorOn)
+	{
+		var parameters = new DynamicParameters();
+		parameters.Add("@FinishedOn", finishedTime, DbType.DateTime, ParameterDirection.Input,50);
+		parameters.Add("@ConnectorId", connectorId, DbType.Int16, ParameterDirection.Input);	
+		parameters.Add("@ChargeBoxId", chargeBoxId, DbType.String, ParameterDirection.Input, 50);
+		parameters.Add("@CreatedOn", previousErrorOn, DbType.DateTime, ParameterDirection.Input, 50);
+
+		using var conn = await sqlConnectionFactory.CreateAsync();
+		await conn.ExecuteAsync("""
+            Update MachineError set FinishedOn=@FinishedOn where
+            ChargeBoxId=@ChargeBoxId and ConnectorId=@ConnectorId and CreatedOn=@CreatedOn
+            """, parameters);
+	}
+
+	private async Task BundleUpdateConnectorStatus(IEnumerable<StatusNotificationParam> statusNotifications)
     {
         using var db = await contextFactory.CreateDbContextAsync();
         using var trans = await db.Database.BeginTransactionAsync();

+ 1 - 1
EVCB_OCPP.WSServer/Service/LocalBusinessService.cs

@@ -24,7 +24,7 @@ namespace EVCB_OCPP.WSServer.Service
             _client = client;
         }
 
-        async public Task<IdTokenInfo> Authorize(string chargeBoxId, string idTag, int? connectorId = null)
+        async public Task<IdTokenInfo> Authorize(string chargeBoxId, string idTag, int? connectorId = null, string source = null)
         {
             await Task.Delay(10);
             IdTokenInfo info = new IdTokenInfo() { IdTagInfo = new IdTagInfo() { status = AuthorizationStatus.Invalid } };

+ 16 - 7
EVCB_OCPP.WSServer/Service/OuterBusinessService.cs

@@ -92,7 +92,7 @@ namespace EVCB_OCPP.WSServer.Service
         }
 
 
-        async public Task<IdTokenInfo> Authorize(string chargeBoxId, string idTag, int? connectorId = null)
+        async public Task<IdTokenInfo> Authorize(string chargeBoxId, string idTag, int? connectorId = null, string source = null)
         {
             //return new IdTokenInfo() { IdTagInfo = new IdTagInfo()
             //{
@@ -107,7 +107,7 @@ namespace EVCB_OCPP.WSServer.Service
             {
                 logger.LogInformation(chargeBoxId + " Charging Monitor======================================>");
 
-                string requestParams = idTag.StartsWith("vid:") ? await GetRequestParamsAsPnC(chargeBoxId, idTag, connectorId) : GetRequestParamsAsNormal(chargeBoxId, idTag);
+                string requestParams = idTag.StartsWith("vid:") ? await GetRequestParamsAsPnC(chargeBoxId, idTag, connectorId, source) : GetRequestParamsAsNormal(chargeBoxId, idTag, source);
 				logger.LogInformation($"{chargeBoxId} Authorize : {signMaterial.APIUrl + requestParams}");
 				HttpResult response = await httpClient.Post(signMaterial.APIUrl + requestParams, new Dictionary<string, string>()
                             {
@@ -267,7 +267,7 @@ namespace EVCB_OCPP.WSServer.Service
             return _customer;
         }
 
-        private async ValueTask<string> GetRequestParamsAsPnC(string chargeBoxId, string idTag, int? connectorId)
+        private async ValueTask<string> GetRequestParamsAsPnC(string chargeBoxId, string idTag, int? connectorId, string source)
         {
             idTag = idTag.Replace("vid:", "");
 
@@ -290,13 +290,22 @@ namespace EVCB_OCPP.WSServer.Service
                     connectorId = -1;
                 }
             }
-
-            return string.Format("charging_auth?ChargeBoxId={0}&ConnectorId={1}&IdTag={2}", chargeBoxId, connectorId, idTag);
+            var requestParamString = string.Format("charging_auth?ChargeBoxId={0}&ConnectorId={1}&IdTag={2}", chargeBoxId, connectorId, idTag);
+            if (!string.IsNullOrEmpty(source))
+            {
+                requestParamString += $"&Action={source}";
+            }
+            return requestParamString;
         }
 
-        private string GetRequestParamsAsNormal(string chargeBoxId, string idTag)
+        private string GetRequestParamsAsNormal(string chargeBoxId, string idTag, string source)
         {
-            return string.Format("charging_auth?ChargeBoxId={0}&IdTag={1}", chargeBoxId, idTag);
+            var requestParamString = string.Format("charging_auth?ChargeBoxId={0}&IdTag={1}", chargeBoxId, idTag);
+            if (!string.IsNullOrEmpty(source))
+            {
+                requestParamString += $"&Action={source}";
+            }
+            return requestParamString;
         }
 
         public Task NotifyConnectorUnplugged(string data)

+ 1 - 1
EVCB_OCPP.WSServer/Service/WsService/WsClientData.cs

@@ -149,7 +149,7 @@ public class WsClientData : WsSession
 
         if (startIndex is not null && stopIndex is not null)
         {
-            msg = buffer.Substring(startIndex.Value, stopIndex.Value - startIndex.Value);
+            msg = buffer.Substring(startIndex.Value, (stopIndex.Value - startIndex.Value)+1);
             buffer = buffer.Substring(stopIndex.Value + 1);
             return true;
         }

+ 12 - 5
EVCB_OCPP.WSServer/appsettings.json

@@ -1,4 +1,11 @@
 {
+  "Kestrel": {
+    "Endpoints": {
+      "Http": {
+        "Url": "http://localhost:80"
+      }
+    }
+  },
   "WSPort": 54089,
   "WSSPort": "",
   "LocalAuthAPI": "",
@@ -18,7 +25,7 @@
       "async": true,
       "f": {
         "type": "File",
-        "keepFileOpen":  false,
+        "keepFileOpen": false,
         "fileName": "/home/logs/server/${shortdate}.log",
         "layout": "${longdate} ${uppercase:${level}} ${message}"
       },
@@ -132,9 +139,9 @@
     }
   },
   "ConnectionStrings": {
-    "ConnectionLogDBContext": "data source=zerova-ev-dev.database.windows.net;initial catalog=StandardOCPP_ConnectionLog;persist security info=True;user id=azdevsoftware;password=1h52dev#az;MultipleActiveResultSets=True;App=EntityFramework;TrustServerCertificate=true;Max Pool Size=200;Connection Lifetime=0;Pooling=true;",
-    "MainDBContext": "data source=zerova-ev-dev.database.windows.net;initial catalog=StandardOCPP_Main;;persist security info=True;user id=azdevsoftware;password=1h52dev#az;MultipleActiveResultSets=True;App=EntityFramework;TrustServerCertificate=true;Max Pool Size=1024;Connection Lifetime=0;Pooling=true;Min Pool Size=150;",
-    "MeterValueDBContext": "data source=zerova-ev-dev.database.windows.net;initial catalog=StandardOCPP_MeterValue;;persist security info=True;user id=azdevsoftware;password=1h52dev#az;MultipleActiveResultSets=True;App=EntityFramework;TrustServerCertificate=true;Max Pool Size=200;Connection Lifetime=0;Pooling=true;",
-    "WebDBContext": "data source=zerova-ev-dev.database.windows.net;initial catalog=StandardOCPP_Web;;persist security info=True;user id=azdevsoftware;password=1h52dev#az;MultipleActiveResultSets=True;App=EntityFramework;TrustServerCertificate=true;Max Pool Size=200;Connection Lifetime=0;Pooling=true;"
+    "ConnectionLogDBContext": "Server=tcp:zerova-evbackend.database.windows.net,1433;initial catalog=StandardOCPP_ConnectionLog;persist security info=True;user id=ev_user;password=Thw2DEa2hZPdg;MultipleActiveResultSets=False;App=EntityFramework;TrustServerCertificate=false;Max Pool Size=500;Min Pool Size=50;Pooling=true;",
+    "MainDBContext": "Server=tcp:zerova-evbackend.database.windows.net,1433;Initial Catalog=StandardOCPP_Main;Persist Security Info=False;User ID=ev_user;Password=Thw2DEa2hZPdg;MultipleActiveResultSets=False;Encrypt=False;TrustServerCertificate=false;ConnectRetryCount=10;ConnectRetryInterval=1;Max Pool Size=4096;Min Pool Size=50;",
+    "MeterValueDBContext": "data source=tcp:zerova-evbackend.database.windows.net,1433;initial catalog=StandardOCPP_MeterValue;;persist security info=True;User ID=ev_user;Password=Thw2DEa2hZPdg;MultipleActiveResultSets=True;App=EntityFramework;TrustServerCertificate=true;Max Pool Size=200;Connection Lifetime=0;Pooling=true;",
+    "WebDBContext": "data source=tcp:zerova-evbackend.database.windows.net,1433;initial catalog=StandardOCPP_Web;;persist security info=True;User ID=ev_user;Password=Thw2DEa2hZPdg;MultipleActiveResultSets=True;App=EntityFramework;TrustServerCertificate=true;Max Pool Size=200;Connection Lifetime=0;Pooling=true;"
   }
 }

+ 1 - 1
version.txt

@@ -1 +1 @@
-Docker_v1.1.21
+Docker_v1.1.23