Browse Source

test pass 1
55 30~50 s

shayne_lo 5 months ago
parent
commit
0ca6e12ce7

+ 1 - 1
EVCB_OCPP.WSServer/GlobalConfig.cs

@@ -168,7 +168,7 @@ namespace EVCB_OCPP.WSServer
         public static DateTime DefaultNullTime = new DateTime(1991, 1, 1);
 
 
-
+        public const string BootData_EVSEConfig_Key = "BootData_EVSEConfig_Key";
 
 
     }

+ 2 - 2
EVCB_OCPP.WSServer/Helper/GroupHandlerIO.cs

@@ -30,12 +30,12 @@ public class GroupHandler<TI,TO> where TI : class
 
     private SemaphoreSlim workersLock;// = new SemaphoreSlim(1);
 
-    public async Task<TO> HandleAsync(TI param)
+    public async Task<TO> HandleAsync(TI param, CancellationToken token = default)
     {
         var waitData = new WaitParam<TI,TO>() { Data = param, Waiter = new SemaphoreSlim(0), Exception = null };
         waitList.Enqueue(waitData);
         TryStartHandler();
-        await waitData.Waiter.WaitAsync();
+        await waitData.Waiter.WaitAsync(token);
         if (waitData.Exception is not null)
         {
             throw waitData.Exception;

+ 87 - 19
EVCB_OCPP.WSServer/ProtalServer.cs

@@ -92,6 +92,20 @@ namespace EVCB_OCPP.WSServer
             this.httpClient = httpClient;
             isInDocker = !string.IsNullOrEmpty(configuration["DOTNET_RUNNING_IN_CONTAINER"]);
 
+            var maxBootCntConfig = configuration["MaxBootCnt"];
+            if (!string.IsNullOrEmpty(maxBootCntConfig) &&
+                int.TryParse(maxBootCntConfig, out var maxBootCntConfigInt))
+            {
+                maxBootCnt = maxBootCntConfigInt;
+            }
+            var bootReservCntConfig = configuration["BootReservCnt"];
+            if (!string.IsNullOrEmpty(bootReservCntConfig) &&
+                int.TryParse(bootReservCntConfig, out var bootReservCntConfigInt))
+            {
+                bootReservCnt = bootReservCntConfigInt;
+            }
+            bootSemaphore = new SemaphoreSlim(maxBootCnt, maxBootCnt);
+
             // = configuration.GetConnectionString("WebDBContext");
             this.profileHandler = serviceProvider.GetService<ProfileHandler>();// new ProfileHandler(configuration, serviceProvider);
             _loadingBalanceService = new LoadingBalanceService(mainDbConnectionFactory, webDbConnectionFactory);
@@ -131,6 +145,9 @@ namespace EVCB_OCPP.WSServer
         private DateTime _CheckLBDt = DateTime.UtcNow;
         private DateTime _CheckDenyListDt = DateTime.UtcNow.AddDays(-1);
         private readonly LoadingBalanceService _loadingBalanceService;// = new LoadingBalanceService();
+        private readonly int maxBootCnt = 10;
+        private readonly int bootReservCnt = 5;
+        private readonly SemaphoreSlim bootSemaphore = new SemaphoreSlim(20, 20);
         private List<StationInfoDto> _StationInfo = new List<StationInfoDto>();
 
         private readonly List<string> needConfirmActions = new List<string>()
@@ -168,7 +185,6 @@ namespace EVCB_OCPP.WSServer
         };
         private CancellationTokenSource _cts = new CancellationTokenSource();
         private CancellationToken _ct;
-        private Semaphore bootSemaphore = new Semaphore(10, 10);
         #endregion
 
         internal Dictionary<string, WsClientData> GetClientDic()
@@ -178,11 +194,17 @@ namespace EVCB_OCPP.WSServer
             return toReturn;
         }
 
+        internal int GetBootLockCnt()
+        {
+            return bootSemaphore.CurrentCount;
+        }
+
         internal IReadOnlyList<Profile> Profiles => profiles.AsReadOnly();
         internal LoadingBalanceService LoadingBalanceService => _loadingBalanceService;
         internal ProfileHandler ProfileHandler => profileHandler;
 
         internal readonly List<Func<WsClientData, CancellationToken, Task>> InitActions = new List<Func<WsClientData, CancellationToken, Task>>();
+        internal readonly List<Func<WsClientData, CancellationToken, Task>> LateInitActions = new List<Func<WsClientData, CancellationToken, Task>>();
 
         public async Task StartAsync(CancellationToken cancellationToken)
         {
@@ -729,16 +751,18 @@ namespace EVCB_OCPP.WSServer
                                     session.ChargePointVendor = bootNotificationRequest.chargePointVendor;
 
                                     if (session.BootStatus == BootStatus.Startup
-                                        //&& bootSemaphore.WaitOne(0)
                                         )
                                     {
+                                        //session.BootStatus = BootStatus.Pending;
                                         session.BootStatus = BootStatus.Initializing;
                                         session.AddTask(StartInitializeEVSE(session));
                                     }
 
-                                    if (bootNotificationConfirmation.status == Packet.Messages.SubTypes.RegistrationStatus.Accepted)
+                                    if (bootNotificationConfirmation.status == Packet.Messages.SubTypes.RegistrationStatus.Accepted
+                                        )
                                     {
                                         session.IsCheckIn = true;
+                                        //session.AddTask(StartAllInitializeEVSE(session));
                                         session.AddTask(StartLateInitializeEVSE(session));
                                         //await confirmWaitingMessageSerevice.SendAndWaitUntilResultAsync(sendTask, session.DisconnetCancellationToken);
                                     }
@@ -1015,8 +1039,28 @@ namespace EVCB_OCPP.WSServer
             }
         }
 
+        private async Task StartAllInitializeEVSE(WsClientData session)
+        {
+            await bootSemaphore.WaitAsync();
+            try
+            {
+                await InitializeEVSE(session);
+                await LateInitializeEVSE(session);
+            }
+            catch (Exception e)
+            {
+                logger.LogCritical("StartAllInitializeEVSE:{errormsg}", e.Message);
+                logger.LogCritical("StartAllInitializeEVSE:{errorStackTrace}", e.StackTrace);
+            }
+            finally
+            {
+                bootSemaphore.Release();
+            }
+        }
+
         private async Task StartInitializeEVSE(WsClientData session)
         {
+            await bootSemaphore.WaitAsync();
             try
             {
                 await InitializeEVSE(session);
@@ -1029,7 +1073,7 @@ namespace EVCB_OCPP.WSServer
             finally
             {
                 session.BootStatus = BootStatus.Pending;
-                //bootSemaphore.Release();
+                bootSemaphore.Release();
             }
         }
 
@@ -1048,15 +1092,19 @@ namespace EVCB_OCPP.WSServer
             var displayPriceText = await webDbService.SetDefaultFee(session);
             UpdateClientDisplayPrice(session.ChargeBoxId, displayPriceText);
 
-            Func<string, Task<string>> sendTask;
-            sendTask = async (string serialNo) => await messageService.SendGetEVSEConfigureRequest(session.ChargeBoxId, serialNo: serialNo);
-            var response = await confirmWaitingMessageSerevice.SendAndWaitUntilResultAsync(sendTask, session.DisconnetCancellationToken);
+            Func<string , CancellationToken , Task<string>> sendTask;
+            sendTask = async (string serialNo, CancellationToken token) => await messageService.SendGetEVSEConfigureRequest(session.ChargeBoxId, serialNo: serialNo, token: token);
+            var response = await confirmWaitingMessageSerevice.SendAndWaitUntilResultAsync(sendTask, token: session.DisconnetCancellationToken);
+            if (response is GetConfigurationConfirmation getConfigurationConfirmation)
+            {
+                session.Data[GlobalConfig.BootData_EVSEConfig_Key] = getConfigurationConfirmation.configurationKey;
+            }
 
             if (!string.IsNullOrEmpty(displayPriceText))
             {
-                sendTask = async (string serialNo) => await messageService.SendChangeConfigurationRequest(
+                sendTask = async (string serialNo, CancellationToken token) => await messageService.SendChangeConfigurationRequest(
                     session.ChargeBoxId, key: "DefaultPrice", value: displayPriceText, serialNo: serialNo);
-                await confirmWaitingMessageSerevice.SendAndWaitUntilResultAsync(sendTask, session.DisconnetCancellationToken);
+                await confirmWaitingMessageSerevice.SendAndWaitResultAsync(sendTask, token: session.DisconnetCancellationToken);
             }
 
             if (session.CustomerId == new Guid("298918C0-6BB5-421A-88CC-4922F918E85E") || session.CustomerId == new Guid("9E6BFDCC-09FB-4DAB-A428-43FE507600A3"))
@@ -1077,14 +1125,26 @@ namespace EVCB_OCPP.WSServer
                 var initFunction = InitActions[index];
                 await initFunction(session, session.DisconnetCancellationToken);
             }
+
+            session.Data.Remove(GlobalConfig.BootData_EVSEConfig_Key);//= getConfigurationConfirmation.configurationKey;
             //await StationConfigService?.CheckAndUpdateEvseConfig(session, session.DisconnetCancellationToken);
         }
 
         private async Task StartLateInitializeEVSE(WsClientData session)
         {
+            bool passed = false;
+            do
+            {
+                while (bootSemaphore.CurrentCount < bootReservCnt)
+                {
+                    await Task.Delay(TimeSpan.FromMinutes(2), session.DisconnetCancellationToken);
+                }
+                passed = bootSemaphore.Wait(0);
+            } while (!passed);
+
             try
             {
-                await Task.Delay(TimeSpan.FromMinutes(5));
+                //await Task.Delay(TimeSpan.FromMinutes(5));
                 await LateInitializeEVSE(session);
             }
             catch (Exception e)
@@ -1094,28 +1154,36 @@ namespace EVCB_OCPP.WSServer
             }
             finally
             {
-                session.BootStatus = BootStatus.Pending;
-                //bootSemaphore.Release();
+                //session.BootStatus = BootStatus.Pending;
+                bootSemaphore.Release();
             }
         }
 
         private async Task LateInitializeEVSE(WsClientData session)
         {
-            Func<string, Task<string>> sendTask; 
+            Func<string, CancellationToken , Task<string>> sendTask; 
 
-            sendTask  = async (string serialNo) => await messageService.SendDataTransferRequest(
+            sendTask  = async (string serialNo, CancellationToken token) => await messageService.SendDataTransferRequest(
                 session.ChargeBoxId,
                 messageId: "ID_FirmwareVersion",
                 vendorId: "Phihong Technology",
                 data: string.Empty,
-                serialNo: serialNo);
-            await confirmWaitingMessageSerevice.SendAndWaitUntilResultAsync(sendTask, session.DisconnetCancellationToken);
+                serialNo: serialNo,
+                token: token);
+            await confirmWaitingMessageSerevice.SendAndWaitResultAsync(sendTask, token: session.DisconnetCancellationToken);
 
-            sendTask = async (string serialNo) => await messageService.SendTriggerMessageRequest(
+            sendTask = async (string serialNo, CancellationToken token) => await messageService.SendTriggerMessageRequest(
                 session.ChargeBoxId,
                 messageTrigger: MessageTrigger.DiagnosticsStatusNotification,
-                serialNo: serialNo);
-            await confirmWaitingMessageSerevice.SendAndWaitUntilResultAsync(sendTask, session.DisconnetCancellationToken);
+                serialNo: serialNo,
+                token: token);
+            await confirmWaitingMessageSerevice.SendAndWaitResultAsync(sendTask, token: session.DisconnetCancellationToken);
+
+            for (var index = 0; index < LateInitActions.Count; index++)
+            {
+                var lateInitFunction = LateInitActions[index];
+                await lateInitFunction(session, session.DisconnetCancellationToken);
+            }
         }
 
         private void Send(WsClientData session, string msg, string messageType, string errorMsg = "")

+ 31 - 8
EVCB_OCPP.WSServer/Service/ConfirmWaitingMessageSerevice.cs

@@ -219,21 +219,44 @@ namespace EVCB_OCPP.WSServer.Service
             return message;
         }
 
-        internal async Task<object> SendAndWaitUntilResultAsync(Func<string, Task> startSendTaskFunc, CancellationToken token = default)
+        internal Task<object> SendAndWaitUntilResultAsync(Func<string, Task> startSendTaskFunc, int maxWaitSec = 180_000, CancellationToken token = default)
+        {
+            Func<string, CancellationToken, Task> func = (string result, CancellationToken token) => startSendTaskFunc(result);
+            return SendAndWaitUntilResultAsync(func, maxWaitSec: maxWaitSec , token: token);
+        }
+
+        internal async Task<object> SendAndWaitUntilResultAsync(Func<string, CancellationToken, Task> startSendTaskFunc, int maxWaitSec = 180_000, CancellationToken token = default)
         {
             object message;
             do
             {
-                var SerialNo = Guid.NewGuid().ToString();
-                var waitObject = CreateAndAddWaitObject(SerialNo);
-                await startSendTaskFunc(SerialNo);
-                message = await WaitResultAsync(SerialNo, waitObject: waitObject, token: token);
+                message = await SendAndWaitResultAsync(startSendTaskFunc, maxWaitSec: maxWaitSec, token: token);
+                //var SerialNo = Guid.NewGuid().ToString();
+                //var waitObject = CreateAndAddWaitObject(SerialNo);
+                //await startSendTaskFunc(SerialNo, token);
+                //message = await WaitResultAsync(SerialNo, waitObject: waitObject, token: token);
             }
             while (message == null && !token.IsCancellationRequested);
             return message;
         }
 
-        internal async Task<object> WaitResultAsync(string serialNo, MessageResultWaitObject waitObject = null, int maxWaitSec = 65000, CancellationToken token = default)
+        internal Task<object> SendAndWaitResultAsync(Func<string, Task> startSendTaskFunc, int maxWaitSec = 1_000, CancellationToken token = default)
+        {
+            Func<string, CancellationToken, Task> func = (string result, CancellationToken token) => startSendTaskFunc(result);
+            return SendAndWaitResultAsync(func, maxWaitSec: maxWaitSec, token: token);
+        }
+
+        internal async Task<object> SendAndWaitResultAsync(Func<string, CancellationToken, Task> startSendTaskFunc, int maxWaitSec = 1_000, CancellationToken token = default)
+        {
+            object message;
+            var SerialNo = Guid.NewGuid().ToString();
+            var waitObject = CreateAndAddWaitObject(SerialNo);
+            await startSendTaskFunc(SerialNo, token);
+            message = await WaitResultAsync(SerialNo, waitObject: waitObject, maxWaitSec: maxWaitSec, token: token);
+            return message;
+        }
+
+        internal async Task<object> WaitResultAsync(string serialNo, MessageResultWaitObject waitObject = null, int maxWaitSec = 180_000, CancellationToken token = default)
         {
             if (waitObject == null)
             {
@@ -242,7 +265,7 @@ namespace EVCB_OCPP.WSServer.Service
             }
 
             var task = waitObject.Lock.WaitAsync(token);
-            var completedTask = await Task.WhenAny(task, Task.Delay(180_000, token));
+            var completedTask = await Task.WhenAny(task, Task.Delay(maxWaitSec, token));
             if (completedTask != task)
             {
                 logger.LogWarning("wait {msg} time out", serialNo);
@@ -257,7 +280,7 @@ namespace EVCB_OCPP.WSServer.Service
             }
 
             asyncWaitingTasks.Remove(serialNo, out var _);
-            return waitObject.Result.Message;
+            return waitObject.Result?.Message;
         }
 
         private MessageResultWaitObject CreateAndAddWaitObject(string serialNo)

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

@@ -40,8 +40,8 @@ public interface IMainDbService
     Task UpdateConnectorStatus(string Id, ConnectorStatus connectorStatus);
     ValueTask AddConnectorStatus(string ChargeBoxId, byte ConnectorId, DateTime CreatedOn, int Status,
         int ChargePointErrorCodeId, string ErrorInfo, string VendorId, string VendorErrorCode);
-    Task<string> AddServerMessage(ServerMessage message);
-    Task<string> AddServerMessage(string ChargeBoxId, string OutAction, object OutRequest, string CreatedBy = "", DateTime? CreatedOn = null, string SerialNo = "", string InMessage = "");
+    Task<string> AddServerMessage(ServerMessage message, CancellationToken token = default);
+    Task<string> AddServerMessage(string ChargeBoxId, string OutAction, object OutRequest, string CreatedBy = "", DateTime? CreatedOn = null, string SerialNo = "", string InMessage = "", CancellationToken token = default);
     ValueTask AddMachineError(byte ConnectorId, DateTime CreatedOn, int Status, string ChargeBoxId, int ErrorCodeId, string ErrorInfo, int PreStatus, string VendorErrorCode, string VendorId);
 	ValueTask FillupFinishedTimetoMachineError(string ChargeBoxId, byte ConnectorId, DateTime FinishedOn);
 
@@ -265,7 +265,7 @@ public class MainDbService : IMainDbService
         return AddFinishedTimetoMachineErrorDapper(ChargeBoxId, ConnectorId, FinishedOn);
     }
 
-    public async Task<string> AddServerMessage(string ChargeBoxId, string OutAction, object OutRequest, string CreatedBy, DateTime? CreatedOn = null, string SerialNo = "", string InMessage = "")
+    public async Task<string> AddServerMessage(string ChargeBoxId, string OutAction, object OutRequest, string CreatedBy, DateTime? CreatedOn = null, string SerialNo = "", string InMessage = "", CancellationToken token = default)
     {
         if (string.IsNullOrEmpty(CreatedBy))
         {
@@ -301,14 +301,14 @@ public class MainDbService : IMainDbService
             InMessage = InMessage
         };
 
-        await AddServerMessage(data);
+        await AddServerMessage(data, token: token);
         return SerialNo;
     }
 
-    public Task<string> AddServerMessage(ServerMessage message)
+    public Task<string> AddServerMessage(ServerMessage message, CancellationToken token = default)
     {
         //return AddServerMessageEF(message);
-        return addServerMessageHandler.HandleAsync(message);
+        return addServerMessageHandler.HandleAsync(message, token);
         //var id = message.SerialNo;
         //await AddServerMessageDapper(message);
         //return id;

+ 11 - 2
EVCB_OCPP.WSServer/Service/DbService/WebDbService.cs

@@ -96,7 +96,11 @@ public class WebDbService
                     """;
 
                 }
-                var result = await conn.QueryFirstOrDefaultAsync<StationFee>(displayPricestrSql, parameters);
+                var result = await conn.QueryFirstOrDefaultAsync<StationFee>(new CommandDefinition(
+                    commandText: displayPricestrSql,
+                    parameters: parameters,
+                    cancellationToken: client.DisconnetCancellationToken
+                    ));
                 if (result == default)
                 {
                     client.IsBilling = false;
@@ -106,7 +110,12 @@ public class WebDbService
 
                 if (stationPrice.BillingMethod == 1)
                 {
-                    var chargingPriceResult = await conn.QueryAsync<ChargingPrice>(strSql, parameters);
+                    //var chargingPriceResult = await conn.QueryAsync<ChargingPrice>(strSql, parameters);
+                    var chargingPriceResult = await conn.QueryAsync<ChargingPrice>(new CommandDefinition(
+                        commandText: strSql,
+                        parameters: parameters,
+                        cancellationToken: client.DisconnetCancellationToken
+                        ));
                     client.ChargingPrices = chargingPriceResult.ToList();
                     if (string.IsNullOrEmpty(client.ChargingPrices[0].StartTime))
                     {

+ 16 - 0
EVCB_OCPP.WSServer/Service/MapApiServce.cs

@@ -132,6 +132,22 @@ public static class MapApiServceExtention
             ThreadPool.SetMaxThreads(max, maxCompletionPortThreads);
             return $"WorkerThread:{avaliableWorkerThread}/{maxWorkerThread} CompletionPortThreads{avaliableCompletionPortThreads}/{maxCompletionPortThreads}";
         }).AddAuthFilter(pass);
+
+        webApplication.MapGet("/blcn", (ProtalServer server) =>
+        {
+            int cnt = server.GetBootLockCnt();
+            return $"boot lock cnt: {cnt}";
+        });
+
+        webApplication.MapGet("/lpcn", (ProtalServer server) =>
+        {
+            Dictionary<string, WsClientData> clientDic = server.GetClientDic();
+            var acceptedCnt = clientDic.Values.Count(x => x.BootStatus == BootStatus.Accepted);
+            var pendingCnt = clientDic.Values.Count(x => x.BootStatus == BootStatus.Pending);
+            var initializingCnt = clientDic.Values.Count(x => x.BootStatus == BootStatus.Initializing);
+            var startupCnt = clientDic.Values.Count(x => x.BootStatus == BootStatus.Startup);
+            return $"IsCheckIn cnt: {startupCnt}/{initializingCnt}/{pendingCnt}/{acceptedCnt}";
+        });
     }
 
     public static void AddAuthFilter(this RouteHandlerBuilder routeHandlerBuilder, string pass)

+ 12 - 8
EVCB_OCPP.WSServer/Service/ServerMessageService.cs

@@ -24,7 +24,7 @@ public class ServerMessageService
     private readonly IMainDbService mainDbService;
     private readonly ILogger<ServerMessageService> logger;
 
-    internal Task<string> SendGetEVSEConfigureRequest(string chargeBoxId, List<string> configKeys = default , string serialNo = "")
+    internal Task<string> SendGetEVSEConfigureRequest(string chargeBoxId, List<string> configKeys = default , string serialNo = "", CancellationToken token = default)
     {
         if (string.IsNullOrEmpty(chargeBoxId)) return null;
         List<string> toPassConfig = configKeys == default ? new List<string>() : configKeys;
@@ -32,11 +32,12 @@ public class ServerMessageService
             ChargeBoxId: chargeBoxId,
             OutAction: Actions.GetConfiguration.ToString(),
             OutRequest: new GetConfigurationRequest() { key = toPassConfig },
-            SerialNo: serialNo
+            SerialNo: serialNo,
+            token: token
             );
     }
 
-    internal Task<string> SendChangeConfigurationRequest(string chargeBoxId, string key, string value, string serialNo = "")
+    internal Task<string> SendChangeConfigurationRequest(string chargeBoxId, string key, string value, string serialNo = "", CancellationToken token = default)
     {
         return mainDbService.AddServerMessage(
             ChargeBoxId: chargeBoxId,
@@ -46,11 +47,12 @@ public class ServerMessageService
                 key = key,
                 value = value
             },
-            SerialNo: serialNo
+            SerialNo: serialNo,
+            token: token
             );
     }
 
-    internal Task<string> SendDataTransferRequest(string chargeBoxId, string messageId, string vendorId, string data, string serialNo = "")
+    internal Task<string> SendDataTransferRequest(string chargeBoxId, string messageId, string vendorId, string data, string serialNo = "", CancellationToken token = default)
     {
         return mainDbService.AddServerMessage(
             ChargeBoxId: chargeBoxId,
@@ -61,11 +63,12 @@ public class ServerMessageService
                 vendorId = vendorId,
                 data = data
             },
-            SerialNo: serialNo
+            SerialNo: serialNo,
+            token: token
             );
     }
 
-    internal Task<string> SendTriggerMessageRequest(string chargeBoxId, MessageTrigger messageTrigger, string serialNo = "")
+    internal Task<string> SendTriggerMessageRequest(string chargeBoxId, MessageTrigger messageTrigger, string serialNo = "", CancellationToken token = default)
     {
         return mainDbService.AddServerMessage(
             ChargeBoxId: chargeBoxId,
@@ -74,7 +77,8 @@ public class ServerMessageService
             {
                 requestedMessage = messageTrigger
             },
-            SerialNo: serialNo
+            SerialNo: serialNo,
+            token: token
             );
     }
 }

+ 18 - 11
EVCB_OCPP.WSServer/Service/StationConfigService.cs

@@ -1,4 +1,5 @@
 using EVCB_OCPP.Packet.Messages.Core;
+using EVCB_OCPP.Packet.Messages.SubTypes;
 using EVCB_OCPP.WSServer.Message;
 using EVCB_OCPP.WSServer.Service.DbService;
 using EVCB_OCPP.WSServer.Service.WsService;
@@ -20,7 +21,7 @@ public static class StationConfigServiceExt
     {
         var server = host.Services.GetRequiredService<ProtalServer>();
         var stationConfigService = host.Services.GetRequiredService<StationConfigService>();
-        server.InitActions.Add(stationConfigService.CheckAndUpdateEvseConfig);
+        server.InitActions.Add(stationConfigService.CheckAndUpdateEvseConfigOnConnnected);
         return host.Services.GetRequiredService<StationConfigService>().Init();
     }
 }
@@ -56,7 +57,7 @@ public class StationConfigService
         stationConfigRecord = await webDbService.GetStationEvseConfigs();
     }
 
-    public async Task CheckAndUpdateEvseConfig(WsClientData session, CancellationToken token = default)
+    public async Task CheckAndUpdateEvseConfigOnConnnected(WsClientData session, CancellationToken token = default)
     {
         var chargeBoxId = session.ChargeBoxId;
         var stationId = await webDbService.GetEvseStation(chargeBoxId, token);
@@ -70,7 +71,9 @@ public class StationConfigService
         if (sessionStationId != stationId)
         {
             SetSessionStation(session, stationId);
-            await UpdateEvseConfig(chargeBoxId, stationId.Value, token);
+
+            var configs = session.Data.ContainsKey(GlobalConfig.BootData_EVSEConfig_Key) ? session.Data[GlobalConfig.BootData_EVSEConfig_Key] as List<KeyValue> : null;
+            await UpdateEvseConfig(chargeBoxId, stationId.Value, evseCurrentKeys: configs, token: token);
         }
         return;
     }
@@ -141,7 +144,7 @@ public class StationConfigService
         }
     }
 
-    private async Task UpdateEvseConfig(string chargeBoxId, int stationId, CancellationToken token = default)
+    private async Task UpdateEvseConfig(string chargeBoxId, int stationId, List<KeyValue> evseCurrentKeys = null, CancellationToken token = default)
     {
         Dictionary<string, string> dbConfigs = null;
 
@@ -152,15 +155,19 @@ public class StationConfigService
         }
         dbConfigs = stationConfigRecord[stationId];
 
-        GetConfigurationConfirmation confirmation = await GetEvseCurrentConfig(chargeBoxId, ConfigKeys: dbConfigs.Keys.ToList(), token: token);
-        if (confirmation is null)
+        if (evseCurrentKeys == null)
         {
-            logger.LogWarning("{chargeBoxId} get config from evse failed", chargeBoxId);
-            return;
+            GetConfigurationConfirmation confirmation = await GetEvseCurrentConfig(chargeBoxId, ConfigKeys: dbConfigs.Keys.ToList(), token: token);
+            if (confirmation is null)
+            {
+                logger.LogWarning("{chargeBoxId} get config from evse failed", chargeBoxId);
+                return;
+            }
+            evseCurrentKeys = confirmation.configurationKey;
         }
 
         Dictionary<string, string> evseCurrentConfigs = new Dictionary<string, string>();
-        evseCurrentConfigs = confirmation.configurationKey.DistinctBy(x=>x.key).ToDictionary(x => x.key, x => x.value);
+        evseCurrentConfigs = evseCurrentKeys.DistinctBy(x=>x.key).ToDictionary(x => x.key, x => x.value);
 
         await CompareAndUpdateConfig(chargeBoxId,
             evseCurrentConfigs: evseCurrentConfigs,
@@ -172,7 +179,7 @@ public class StationConfigService
     private async Task<GetConfigurationConfirmation> GetEvseCurrentConfig(string chargeBoxId, List<string> ConfigKeys = default, CancellationToken token = default)
     {
         var sendTask = async (string serialNo) => await messageService.SendGetEVSEConfigureRequest(chargeBoxId, configKeys: ConfigKeys, serialNo: serialNo);
-        var response = await confirmWaitingMessageSerevice.SendAndWaitUntilResultAsync(sendTask, token);
+        var response = await confirmWaitingMessageSerevice.SendAndWaitUntilResultAsync(sendTask, token: token);
         if (response is GetConfigurationConfirmation confirmation)
         {
             return confirmation;
@@ -213,7 +220,7 @@ public class StationConfigService
 
             object response = null;
             var sendTask = async (string serialNo) => await messageService.SendChangeConfigurationRequest(chargeBoxId, config.Key, config.Value, serialNo: serialNo);
-            response = await confirmWaitingMessageSerevice.SendAndWaitUntilResultAsync(sendTask, token);
+            response = await confirmWaitingMessageSerevice.SendAndWaitResultAsync(sendTask, token: token);
         }
     }
 

+ 2 - 0
EVCB_OCPP.WSServer/appsettings.json

@@ -14,6 +14,8 @@
   "OCPP20_WSUrl": "ws://ocpp.phihong.com.tw:5004",
   "OCPP20_WSSUrl": "ws://ocpp.phihong.com.tw:5004",
   "MaintainMode": 0,
+  "MaxBootCnt": 10,
+  "BootReservCnt": 5,
   "Logging": {
     "LogLevel": {
       "Default": "Information",