Bladeren bron

test pass , 200 EVSE at startup

Robert 1 jaar geleden
bovenliggende
commit
c36fd9b61a

+ 47 - 0
EVCB_OCPP.WSServer/Helper/SemaphoreWrapper.cs

@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace EVCB_OCPP.WSServer.Helper;
+
+public class SemaphoreWrapper : IDisposable
+{
+
+    public async static Task<SemaphoreWrapper> WaitAsync(SemaphoreSlim semaphore)
+    {
+        var toReturn = new SemaphoreWrapper(semaphore);
+        await semaphore.WaitAsync();
+        toReturn.isLockAquired = true;
+        return toReturn;
+    }
+
+    public async static Task<SemaphoreWrapper> TryGet(SemaphoreSlim semaphore)
+    {
+        var toReturn = new SemaphoreWrapper(semaphore);
+        if (semaphore.Wait(0))
+        {
+            toReturn.isLockAquired = true;
+            return toReturn;
+        }
+        return null;
+    }
+
+    private SemaphoreWrapper(SemaphoreSlim semaphore)
+    {
+        this.semaphore = semaphore;
+    }
+
+    public void Dispose()
+    {
+        if (isLockAquired)
+        {
+            semaphore.Release();
+        }
+    }
+
+    private readonly SemaphoreSlim semaphore;
+    private bool isLockAquired = false;
+}

+ 19 - 18
EVCB_OCPP.WSServer/Message/CoreProfileHandler.cs

@@ -77,6 +77,7 @@ internal partial class ProfileHandler
     private readonly IDbContextFactory<MainDBContext> maindbContextFactory;
     private readonly IDbContextFactory<MeterValueDBContext> metervaluedbContextFactory;
     private readonly IServiceProvider serviceProvider;
+    private readonly MainDbService mainDbService;
     private readonly string mainDbConnectionString;
     private OuterHttpClient httpClient = new OuterHttpClient();
 
@@ -84,13 +85,15 @@ internal partial class ProfileHandler
         IConfiguration configuration,
         IDbContextFactory<MainDBContext> maindbContextFactory, 
         IDbContextFactory<MeterValueDBContext> metervaluedbContextFactory,
-        IServiceProvider serviceProvider)
+        IServiceProvider serviceProvider,
+        MainDbService mainDbService)
     {
         webConnectionString = configuration.GetConnectionString("WebDBContext");
         logger = serviceProvider.GetService<ILogger<ProfileHandler>>();
 
         this.maindbContextFactory = maindbContextFactory;
         this.serviceProvider = serviceProvider;
+        this.mainDbService = mainDbService;
         this.metervaluedbContextFactory = metervaluedbContextFactory;
         this.mainDbConnectionString = configuration.GetConnectionString("MainDBContext");
     }
@@ -202,23 +205,23 @@ internal partial class ProfileHandler
                     {
                         BootNotificationRequest _request = request as BootNotificationRequest;
                         int heartbeat_interval = GlobalConfig.GetHEARTBEAT_INTERVAL();
+                        //var _machine = db.Machine.FirstOrDefault(x => x.ChargeBoxId == session.ChargeBoxId);
+                        Machine _machine = new();
+                        _machine.ChargeBoxSerialNumber = string.IsNullOrEmpty(_request.chargeBoxSerialNumber) ? string.Empty : _request.chargeBoxSerialNumber;
+                        _machine.ChargePointSerialNumber = string.IsNullOrEmpty(_request.chargePointSerialNumber) ? string.Empty : _request.chargePointSerialNumber;
+                        _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.Iccid = DateTime.UtcNow.ToString("yy-MM-dd HH:mm");
+                        _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;
+
+                        await mainDbService.UpdateMachineBasicInfo(session.ChargeBoxId, _machine);
+
                         using (var db = maindbContextFactory.CreateDbContext())
                         {
-                            var _machine = db.Machine.FirstOrDefault(x => x.ChargeBoxId == session.ChargeBoxId);
-                            _machine.ChargeBoxSerialNumber = string.IsNullOrEmpty(_request.chargeBoxSerialNumber) ? string.Empty : _request.chargeBoxSerialNumber;
-                            _machine.ChargePointSerialNumber = string.IsNullOrEmpty(_request.chargePointSerialNumber) ? string.Empty : _request.chargePointSerialNumber;
-                            _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.Iccid = DateTime.UtcNow.ToString("yy-MM-dd HH:mm");
-                            _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();
-                            db.ChangeTracker.Clear();
-
                             var configVaule = await db.MachineConfigurations
                                 .Where(x => x.ChargeBoxId == session.ChargeBoxId && x.ConfigureName == StandardConfiguration.HeartbeatInterval)
                                 .Select(x => x.ConfigureSetting)
@@ -900,7 +903,6 @@ internal partial class ProfileHandler
         {
             switch (action)
             {
-
                 case Actions.DataTransfer:
                     {
                         DataTransferConfirmation _confirm = confirm as DataTransferConfirmation;
@@ -1374,7 +1376,6 @@ internal partial class ProfileHandler
                         }
                     }
                     break;
-
                 case Actions.ClearCache:
                     {
                         ClearCacheConfirmation _confirm = confirm as ClearCacheConfirmation;

+ 1 - 0
EVCB_OCPP.WSServer/Program.cs

@@ -89,6 +89,7 @@ namespace EVCB_OCPP.WSServer
                     services.AddSingleton<BusinessServiceFactory>();
 
                     //services.AddHostedService<ProtalServer>();
+                    services.AddSingleton<MainDbService>();
 
                     services.AddProtalServer();
                 })

+ 2 - 1
EVCB_OCPP.WSServer/ProtalServer.cs

@@ -482,7 +482,8 @@ namespace EVCB_OCPP.WSServer
             //載入OCPP Protocol
             var appServer = new OCPPWSServer(
                 new List<OCPPSubProtocol>() { new OCPPSubProtocol(), new OCPPSubProtocol(" ocpp1.6"), new OCPPSubProtocol("ocpp2.0") }
-                ,serviceProvider);
+                ,serviceProvider
+                , serviceProvider.GetRequiredService<MainDbService>());
 
             List<IListenerConfig> llistener = new List<IListenerConfig>();
 

+ 78 - 0
EVCB_OCPP.WSServer/Service/MainDbService.cs

@@ -0,0 +1,78 @@
+using EVCB_OCPP.Domain;
+using EVCB_OCPP.Domain.Models.Database;
+using EVCB_OCPP.WSServer.Helper;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.DependencyInjection;
+using OCPPPackage.Profiles;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace EVCB_OCPP.WSServer.Service;
+
+public class MainDbService
+{
+    public MainDbService(IDbContextFactory<MainDBContext> contextFactory)
+    {
+        this.contextFactory = contextFactory;
+
+        this.semaphore = new SemaphoreSlim(5);
+    }
+
+    private readonly IDbContextFactory<MainDBContext> contextFactory;
+    private readonly SemaphoreSlim semaphore;
+
+    public async Task<MachineAndCustomerInfo> GetMachineIdAndCustomerInfo(string ChargeBoxId)
+    {
+        using var semaphoreWrapper = await SemaphoreWrapper.WaitAsync(semaphore);
+        using var db = contextFactory.CreateDbContext();
+        var machine = await db.Machine.Where(x => x.ChargeBoxId == ChargeBoxId && x.IsDelete == false).Select(x => new { x.CustomerId, x.Id }).AsNoTracking().FirstOrDefaultAsync();
+        if (machine == null) {
+            return new MachineAndCustomerInfo(string.Empty, Guid.Empty, "Unknown");
+        }
+        var customerName = await db.Customer.Where(x => x.Id == machine.CustomerId).Select(x => x.Name).FirstOrDefaultAsync();
+        return new MachineAndCustomerInfo(machine.Id, machine.CustomerId, customerName);
+    }
+
+    public async Task<string> GetMachineSecurityProfile(string ChargeBoxId)
+    {
+        using var semaphoreWrapper = await SemaphoreWrapper.WaitAsync(semaphore);
+        using var db = contextFactory.CreateDbContext();
+        return await db.MachineConfigurations
+            .Where(x => x.ChargeBoxId == ChargeBoxId && x.ConfigureName == StandardConfiguration.SecurityProfile)
+            .Select(x => x.ConfigureSetting).FirstOrDefaultAsync();
+    }
+
+    public async Task<string> GetMachineAuthorizationKey(string ChargeBoxId)
+    {
+        using var semaphoreWrapper = await SemaphoreWrapper.WaitAsync(semaphore);
+        using var db = contextFactory.CreateDbContext();
+        return await db.MachineConfigurations
+            .Where(x => x.ChargeBoxId == ChargeBoxId && x.ConfigureName == StandardConfiguration.AuthorizationKey)
+            .Select(x => x.ConfigureSetting).FirstOrDefaultAsync();
+    }
+
+    public async Task UpdateMachineBasicInfo(string ChargeBoxId, Machine machine)
+    {
+        using var semaphoreWrapper = await SemaphoreWrapper.WaitAsync(semaphore);
+        using var db = contextFactory.CreateDbContext();
+        var _machine = db.Machine.FirstOrDefault(x => x.ChargeBoxId == ChargeBoxId);
+        _machine.ChargeBoxSerialNumber = machine.ChargeBoxSerialNumber;
+        _machine.ChargePointSerialNumber = machine.ChargePointSerialNumber;
+        _machine.ChargePointModel = machine.ChargePointModel;
+        _machine.ChargePointVendor = machine.ChargePointVendor;
+        _machine.FW_CurrentVersion = machine.FW_CurrentVersion;
+        //_machine.Iccid = string.IsNullOrEmpty(_request.iccid) ? string.Empty : _request.iccid;
+        _machine.Iccid = DateTime.UtcNow.ToString("yy-MM-dd HH:mm");
+        _machine.Imsi = machine.Imsi;
+        _machine.MeterSerialNumber = machine.MeterSerialNumber;
+        _machine.MeterType = machine.MeterType;
+
+        await db.SaveChangesAsync();
+    }
+}
+
+public record MachineAndCustomerInfo (string MachineId, Guid CustomerId, string CustomerName);

+ 44 - 40
EVCB_OCPP.WSServer/SuperSocket.Protocol/OCPPWSServer.cs

@@ -1,5 +1,6 @@
 
 using EVCB_OCPP.Domain;
+using EVCB_OCPP.WSServer.Service;
 using Microsoft.EntityFrameworkCore;
 using Microsoft.EntityFrameworkCore.Internal;
 using Microsoft.Extensions.Configuration;
@@ -26,6 +27,7 @@ namespace OCPPServer.Protocol
         static private ILogger logger;
         private readonly IConfiguration configuration;
         private readonly IServiceProvider serviceProvider;
+        private readonly MainDbService mainDbService;
 
         /// <summary>
         /// 可允許連線Clinet數
@@ -41,12 +43,13 @@ namespace OCPPServer.Protocol
         /// Initializes a new instance of the <see cref="WebSocketServer"/> class.
         /// </summary>
         /// <param name="subProtocols">The sub protocols.</param>
-        public OCPPWSServer(IEnumerable<ISubProtocol<ClientData>> subProtocols, IServiceProvider serviceProvider)
+        public OCPPWSServer(IEnumerable<ISubProtocol<ClientData>> subProtocols, IServiceProvider serviceProvider
+            ,MainDbService mainDbService)
             : base(subProtocols)
         {
             this.configuration = serviceProvider.GetService<IConfiguration>();
             this.serviceProvider = serviceProvider;
-
+            this.mainDbService = mainDbService;
             logger = serviceProvider.GetService<ILogger<OCPPWSServer>>();
         }
 
@@ -107,40 +110,45 @@ namespace OCPPServer.Protocol
             logger.LogInformation(string.Format("ValidateHandshake: {0}", session.Path));
             bool isExistedSN = false;
             bool authorizated = false;
-            using (var db = serviceProvider.GetService<IDbContextFactory<MainDBContext>>().CreateDbContext())
-            {
-                var machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.IsDelete == false).Select(x => new { x.CustomerId, x.Id }).AsNoTracking().FirstOrDefault();
-                session.CustomerName = machine == null ? "Unknown" : db.Customer.Where(x => x.Id == machine.CustomerId).Select(x => x.Name).FirstOrDefault();
-                session.CustomerId = machine == null ? Guid.Empty : machine.CustomerId;
-                session.MachineId = machine == null ? String.Empty : machine.Id;
-                isExistedSN = machine == null ? false : true;
 
-                if (!isExistedSN)
-                {
-                    StringBuilder responseBuilder = new StringBuilder();
+            var info = mainDbService.GetMachineIdAndCustomerInfo(session.ChargeBoxId).Result;
+            //var machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.IsDelete == false).Select(x => new { x.CustomerId, x.Id }).AsNoTracking().FirstOrDefault();
+            //session.CustomerName = machine == null ? "Unknown" : db.Customer.Where(x => x.Id == machine.CustomerId).Select(x => x.Name).FirstOrDefault();
+            //session.CustomerId = machine == null ? Guid.Empty : machine.CustomerId;
+            //session.MachineId = machine == null ? String.Empty : machine.Id;
+            //isExistedSN = machine == null ? false : true;
+            session.CustomerName = info.CustomerName;
+            session.CustomerId = info.CustomerId;
+            session.MachineId = info.MachineId;
+            isExistedSN = !string.IsNullOrEmpty(info.MachineId);// machine == null ? false : true;
+
+            if (!isExistedSN)
+            {
+                StringBuilder responseBuilder = new StringBuilder();
 
-                    responseBuilder.AppendFormatWithCrCf(@"HTTP/{0} {1} {2}", "1.1",
-                    (int)HttpStatusCode.NotFound, @"Not Found");
+                responseBuilder.AppendFormatWithCrCf(@"HTTP/{0} {1} {2}", "1.1",
+                (int)HttpStatusCode.NotFound, @"Not Found");
                   
-                    responseBuilder.AppendWithCrCf();
-                    string sb = responseBuilder.ToString();
-                    byte[] data = Encoding.UTF8.GetBytes(sb);
-                    ((IWebSocketSession)session).SendRawData(data, 0, data.Length);
+                responseBuilder.AppendWithCrCf();
+                string sb = responseBuilder.ToString();
+                byte[] data = Encoding.UTF8.GetBytes(sb);
+                ((IWebSocketSession)session).SendRawData(data, 0, data.Length);
 
-                    logger.LogInformation(sb);
-                    return false;
-                }
+                logger.LogInformation(sb);
+                return false;
+            }
 
-                var configVaule = db.MachineConfigurations.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.ConfigureName == StandardConfiguration.SecurityProfile)
-                                  .Select(x => x.ConfigureSetting).FirstOrDefault();
-                int.TryParse(configVaule, out securityProfile);
+            //var configVaule = db.MachineConfigurations.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.ConfigureName == StandardConfiguration.SecurityProfile)
+            //                  .Select(x => x.ConfigureSetting).FirstOrDefault();
+            var configVaule = mainDbService.GetMachineSecurityProfile(session.ChargeBoxId).Result;
+            int.TryParse(configVaule, out securityProfile);
 
-                if (session.ISOCPP20)
-                {
-                    // 1.6 server only support change server  function
-                    securityProfile = 0;
-                }
+            if (session.ISOCPP20)
+            {
+                // 1.6 server only support change server  function
+                securityProfile = 0;
             }
+            
             if (securityProfile == 3 && session.UriScheme == "ws")
             {
                 StringBuilder responseBuilder = new StringBuilder();
@@ -166,20 +174,16 @@ namespace OCPPServer.Protocol
 
                 if (session.Items.ContainsKey("Authorization") || session.Items.ContainsKey("authorization"))
                 {
+                    //authorizationKey = db.MachineConfigurations.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.ConfigureName == StandardConfiguration.AuthorizationKey)
+                    //                    .Select(x => x.ConfigureSetting).FirstOrDefault();
+                    authorizationKey = mainDbService.GetMachineAuthorizationKey(session.ChargeBoxId).Result;
 
-                    using (var db = serviceProvider.GetService<IDbContextFactory<MainDBContext>>().CreateDbContext())
+                    if (session.ISOCPP20)
                     {
-
-                        authorizationKey = db.MachineConfigurations.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.ConfigureName == StandardConfiguration.AuthorizationKey)
-                                          .Select(x => x.ConfigureSetting).FirstOrDefault();
-
-
-                        if (session.ISOCPP20)
-                        {
-                            // 1.6 server only support change server  function
-                            securityProfile = 0;
-                        }
+                        // 1.6 server only support change server  function
+                        securityProfile = 0;
                     }
+                    
                     logger.LogInformation("***********Authorization   ");
 
                     if (!string.IsNullOrEmpty(authorizationKey))