Browse Source

2020/05/05 Jessica
Actions:
1.Add LoadingBalance Service

Jessica.Tseng 4 năm trước cách đây
mục cha
commit
caacc51642

+ 5 - 4
EVCB_OCPP.WSServer/App.config

@@ -11,10 +11,11 @@
     <add name="MainDBContext" connectionString="data source=172.1.0.142\SQLEXPRESS;initial catalog=OCPP_MainDBContext;;persist security info=True;user id=sa;password=Ph0930118811;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />
     <add name="MeterValueDBContext" connectionString="data source=172.1.0.142\SQLEXPRESS;initial catalog=OCPP_MeterValueDBContext;;persist security info=True;user id=sa;password=Ph0930118811;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />-->
    <add name="ConnectionLogDBContext" connectionString="data source=172.1.2.187\SQLEXPRESS2017;initial catalog=StandardOCPP_ConnectionLog;persist security info=True;user id=sa;password=Ph0930118811;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />
-    <add name="MainDBContext" connectionString="data source=172.1.2.187\SQLEXPRESS2017;initial catalog=StandardOCPP_Main;;persist security info=True;user id=sa;password=Ph0930118811;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />
-    <add name="MeterValueDBContext" connectionString="data source=172.1.2.187\SQLEXPRESS2017;initial catalog=StandardOCPP_MeterValue;;persist security info=True;user id=sa;password=Ph0930118811;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />
- 
-  </connectionStrings>
+   <add name="MainDBContext" connectionString="data source=172.1.2.187\SQLEXPRESS2017;initial catalog=StandardOCPP_Main;persist security info=True;user id=sa;password=Ph0930118811;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />
+   <add name="MeterValueDBContext" connectionString="data source=172.1.2.187\SQLEXPRESS2017;initial catalog=StandardOCPP_MeterValue;persist security info=True;user id=sa;password=Ph0930118811;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />
+   <add name="WebDBContext" connectionString="data source=172.1.2.187\SQLEXPRESS2017;initial catalog=StandardOCPP_Web;persist security info=True;user id=sa;password=Ph0930118811;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />
+
+   </connectionStrings>
   <appSettings>
     <add key="ServerIP" value="" />
     <add key="WSPort" value="8080" />

+ 4 - 0
EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj

@@ -33,6 +33,9 @@
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
   <ItemGroup>
+    <Reference Include="Dapper, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <HintPath>..\packages\Dapper.2.0.30\lib\net461\Dapper.dll</HintPath>
+    </Reference>
     <Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
       <HintPath>..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.dll</HintPath>
     </Reference>
@@ -127,6 +130,7 @@
     <Compile Include="Dto\ErrorDetails.cs" />
     <Compile Include="Service\BusinessServiceFactory.cs" />
     <Compile Include="Service\HttpClientService.cs" />
+    <Compile Include="Service\LoadingBalanceService.cs" />
     <Compile Include="Service\LocalBusinessService.cs" />
     <Compile Include="Service\OuterBusinessService.cs" />
     <Compile Include="Dto\ConnectorErrorStauts.cs" />

+ 43 - 43
EVCB_OCPP.WSServer/Message/CoreProfileHandler.cs

@@ -67,43 +67,43 @@ namespace EVCB_OCPP.WSServer.Message
                     {
                         //只保留最新上報狀況
                         StatusNotificationRequest _request = request as StatusNotificationRequest;
-
+                        int preStatus = 0;
+                        using (var db = new MainDBContext())
                         {
-                            List<string> removeIds = new List<string>();
-                            ConnectorErrorStauts _oldStatus = null;
-                            using (var oldDB = new MainDBContext())
+                            var _oldStatus = db.ConnectorStatus.Where(x => x.ChargeBoxId == session.ChargeBoxId
+                          && x.ConnectorId == _request.connectorId).AsNoTracking().FirstOrDefault();
+
+
+                            if (_oldStatus != null && (_request.status != (ChargePointStatus)_oldStatus.Status || _request.status == ChargePointStatus.Faulted))
                             {
-                                _oldStatus = oldDB.ConnectorStatus.Where(x => x.ChargeBoxId == session.ChargeBoxId
-                             && x.ConnectorId == _request.connectorId).Select(x => new ConnectorErrorStauts
-                             {
-                                 Status = x.Status,
-                                 ChargePointErrorCodeId = x.ChargePointErrorCodeId,
-                                 ErrorInfo = x.ErrorInfo,
-                                 VendorId = x.VendorId,
-                                 VendorErrorCode = x.VendorErrorCode
-                             }).AsNoTracking().FirstOrDefault();
-
-
-                                if (_oldStatus!= null && (_request.status != (ChargePointStatus)_oldStatus.Status || _request.status == ChargePointStatus.Faulted))
-                                {
-                                    removeIds = oldDB.ConnectorStatus.Where(x => x.ChargeBoxId == session.ChargeBoxId
-                               && x.ConnectorId == _request.connectorId).Select(x => x.Id).AsNoTracking().ToList();
 
-                                }
+                                preStatus = _oldStatus.Status;
 
-                            }
-                     
+                                db.Configuration.AutoDetectChangesEnabled = false;
+                                db.Configuration.ValidateOnSaveEnabled = false;
+                                db.ConnectorStatus.Attach(_oldStatus);
 
-                            using (var db = new MainDBContext())
-                            {
-                                foreach (var id in removeIds)
-                                {
 
-                                    string query = "DELETE FROM [dbo].[ConnectorStatus] WHERE [Id]={0} ";
-                                    db.Database.ExecuteSqlCommand(query, id);
-                                }
+                                _oldStatus.CreatedOn = _request.timestamp.HasValue ? _request.timestamp.Value : DateTime.Now;
+                                _oldStatus.Status = (int)_request.status;
+                                _oldStatus.ChargePointErrorCodeId = (int)_request.errorCode;
+                                _oldStatus.ErrorInfo = string.IsNullOrEmpty(_request.info) ? string.Empty : _request.info;
+                                _oldStatus.VendorId = string.IsNullOrEmpty(_request.vendorId) ? string.Empty : _request.vendorId;
+                                _oldStatus.VendorErrorCode = string.IsNullOrEmpty(_request.vendorErrorCode) ? string.Empty : _request.vendorErrorCode;
 
-                                db.SaveChanges();
+
+                                db.Entry(_oldStatus).Property(x => x.CreatedOn).IsModified = true;
+                                db.Entry(_oldStatus).Property(x => x.Status).IsModified = true;
+                                db.Entry(_oldStatus).Property(x => x.ChargePointErrorCodeId).IsModified = true;
+                                db.Entry(_oldStatus).Property(x => x.ErrorInfo).IsModified = true;
+                                db.Entry(_oldStatus).Property(x => x.VendorId).IsModified = true;
+                                db.Entry(_oldStatus).Property(x => x.VendorErrorCode).IsModified = true;
+
+
+                            }
+
+                            if (_oldStatus == null)
+                            {
                                 var _currentStatus = new Domain.Models.Database.ConnectorStatus()
                                 {
                                     ChargeBoxId = session.ChargeBoxId,
@@ -111,13 +111,14 @@ namespace EVCB_OCPP.WSServer.Message
                                     CreatedOn = _request.timestamp.HasValue ? _request.timestamp.Value : DateTime.Now,
                                     Status = (int)_request.status,
                                     ChargePointErrorCodeId = (int)_request.errorCode,
-                                    ErrorInfo = _request.info,
-                                    VendorId = _request.vendorId,
-                                    VendorErrorCode = _request.vendorErrorCode,
+                                    ErrorInfo = string.IsNullOrEmpty(_request.info) ? string.Empty : _request.info,
+                                    VendorId = string.IsNullOrEmpty(_request.vendorId) ? string.Empty : _request.vendorId,
+                                    VendorErrorCode = string.IsNullOrEmpty(_request.vendorErrorCode) ? string.Empty : _request.vendorErrorCode,
                                     Id = Guid.NewGuid().ToString()
                                 };
                                 db.ConnectorStatus.Add(_currentStatus);
 
+
                                 if (_request.status == Packet.Messages.SubTypes.ChargePointStatus.Faulted)
                                 {
                                     db.MachineError.Add(new MachineError()
@@ -127,18 +128,17 @@ namespace EVCB_OCPP.WSServer.Message
                                         Status = (int)_request.status,
                                         ChargeBoxId = session.ChargeBoxId,
                                         ErrorCodeId = (int)_request.errorCode,
-                                        ErrorInfo = _request.info,
-                                        PreStatus = _oldStatus==null ? -1:_oldStatus.Status,
-                                        VendorErrorCode = _request.vendorErrorCode,
-                                        VendorId = _request.vendorId
+                                        ErrorInfo = string.IsNullOrEmpty(_request.info) ? string.Empty : _request.info,
+                                        PreStatus = _oldStatus == null ? -1 : preStatus,
+                                        VendorErrorCode = string.IsNullOrEmpty(_request.vendorErrorCode) ? string.Empty : _request.vendorErrorCode,
+                                        VendorId = string.IsNullOrEmpty(_request.vendorId) ? string.Empty : _request.vendorId
                                     });
                                 }
-
-
-                                db.SaveChanges();
                             }
+                            db.SaveChanges();
                         }
 
+
                         if (_request.status == Packet.Messages.SubTypes.ChargePointStatus.Faulted)
                         {
                             var businessService = BusinessServiceFactory.CreateBusinessService(session.CustomerId.ToString(), false);
@@ -147,9 +147,9 @@ namespace EVCB_OCPP.WSServer.Message
                                 ChargeBoxId = session.ChargeBoxId,
                                 ConnectorId = _request.connectorId,
                                 ErrorCode = _request.errorCode,
-                                Info = _request.info,
-                                OCcuredOn = _request.timestamp.Value,
-                                VendorErrorCode = _request.vendorErrorCode,
+                                Info = string.IsNullOrEmpty(_request.info) ? string.Empty : _request.info,
+                                OCcuredOn = _request.timestamp.HasValue ? _request.timestamp.Value : DateTime.Now,
+                                VendorErrorCode = string.IsNullOrEmpty(_request.vendorErrorCode) ? string.Empty : _request.vendorErrorCode,
 
                             });
                         }

+ 74 - 1
EVCB_OCPP.WSServer/Message/SmartChargingProfileHandler.cs

@@ -1,7 +1,9 @@
 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.SmartCharging;
+using EVCB_OCPP.Packet.Messages.SubTypes;
 using Newtonsoft.Json;
 using OCPPServer.Protocol;
 using System;
@@ -16,6 +18,77 @@ namespace EVCB_OCPP.WSServer.Message
     {
 
 
+        internal void SetChargingProfile(string chargeBoxId, decimal value, ChargingRateUnitType unit)
+        {
+            using (var db = new MainDBContext())
+            {
+                var _setProfileRequest = new SetChargingProfileRequest()
+                {
+                    connectorId = 0,
+                    csChargingProfiles = new Packet.Messages.SubTypes.csChargingProfiles()
+                    {
+                        chargingProfileId = 1,
+                        chargingProfileKind = Packet.Messages.SubTypes.ChargingProfileKindType.Recurring,
+                        chargingProfilePurpose = Packet.Messages.SubTypes.ChargingProfilePurposeType.ChargePointMaxProfile,
+                        chargingSchedule = new Packet.Messages.SubTypes.ChargingSchedule()
+                        {
+                            chargingRateUnit = unit,
+                            chargingSchedulePeriod = new List<Packet.Messages.SubTypes.ChargingSchedulePeriod>()
+                                                    {
+                                                        new Packet.Messages.SubTypes.ChargingSchedulePeriod(){  startPeriod=0, limit=value*1000}
+                                                    },
+                            duration = 60,
+
+                        },
+                        recurrencyKind = Packet.Messages.SubTypes.RecurrencyKindType.Daily,
+                        stackLevel = 1,
+
+                    }
+                };
+
+                db.ServerMessage.Add(new ServerMessage()
+                {
+                    ChargeBoxId = chargeBoxId,
+                    CreatedBy = "Server",
+                    CreatedOn = DateTime.Now,
+                    OutAction = _setProfileRequest.Action.ToString(),
+                    OutRequest = JsonConvert.SerializeObject(_setProfileRequest, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                    SerialNo = Guid.Empty.ToString(),
+                    InMessage = string.Empty
+
+                });
+                db.SaveChanges();
+            }
+        }
+
+
+        internal void ClearChargingProfile(string chargeBoxId)
+        {
+            using (var db = new MainDBContext())
+            {
+                var _clearProfileRequest = new ClearChargingProfileRequest()
+                {
+                    connectorId = 0,
+                    chargingProfilePurpose = ChargingProfilePurposeType.ChargePointMaxProfile,              
+
+                };
+
+                db.ServerMessage.Add(new ServerMessage()
+                {
+                    ChargeBoxId = chargeBoxId,
+                    CreatedBy = "Server",
+                    CreatedOn = DateTime.Now,
+                    OutAction = _clearProfileRequest.Action.ToString(),
+                    OutRequest = JsonConvert.SerializeObject(_clearProfileRequest, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                    SerialNo = Guid.Empty.ToString(),
+                    InMessage = string.Empty
+
+                });
+
+                db.SaveChanges();
+            }
+        }
+
 
 
 
@@ -80,7 +153,7 @@ namespace EVCB_OCPP.WSServer.Message
                                 operation.FinishedOn = DateTime.Now;
                                 operation.Status = 1;//電樁有回覆
                                 operation.EVSE_Status = (int)_confirm.status;//OK
-                                operation.EVSE_Value= JsonConvert.SerializeObject(_confirm.chargingSchedule, Formatting.None);
+                                operation.EVSE_Value = JsonConvert.SerializeObject(_confirm.chargingSchedule, Formatting.None);
                                 db.SaveChanges();
                             }
 

+ 86 - 11
EVCB_OCPP.WSServer/ProtalServer.cs

@@ -30,6 +30,8 @@ using System.Configuration;
 using System.Net;
 using System.Net.Security;
 using System.Security.Cryptography.X509Certificates;
+using EVCB_OCPP.WSServer.Service;
+using EVCB_OCPP.Packet.Messages.SmartCharging;
 
 namespace EVCB_OCPP.WSServer
 {
@@ -44,6 +46,7 @@ namespace EVCB_OCPP.WSServer
         private ProfileHandler profileHandler = new ProfileHandler();
         private List<NeedConfirmMessage> needConfirmPacketList = new List<NeedConfirmMessage>();
         private DateTime checkUpdateDt = DateTime.Now;
+        private LoadingBalanceService _loadingBalanceService = new LoadingBalanceService();
         private List<string> needConfirmActions = new List<string>()
         {
              "GetConfiguration",
@@ -110,8 +113,8 @@ namespace EVCB_OCPP.WSServer
             serverUpdateTask.Start();
 
 
-          //  Task serverHealthTask = new Task(HealthAlarmTrigger, _ct);
-           // serverHealthTask.Start();
+            //  Task serverHealthTask = new Task(HealthAlarmTrigger, _ct);
+            // serverHealthTask.Start();
 
             while (true)
             {
@@ -253,10 +256,10 @@ namespace EVCB_OCPP.WSServer
                     takeCount = StandardConfiguration.AllConfigs.Count - skipCount > takeCount ? takeCount : StandardConfiguration.AllConfigs.Count - skipCount;
 
                     var _keys = StandardConfiguration.AllConfigs.Skip(skipCount).Take(takeCount).ToList();
-                 //   Console.WriteLine("===============Skip:" + skipCount);
+                    //   Console.WriteLine("===============Skip:" + skipCount);
                     if (_Configure == null)
                     {
-                       // Console.WriteLine("_Configure == null===============Skip:" + skipCount);
+                        // Console.WriteLine("_Configure == null===============Skip:" + skipCount);
                         db.ServerMessage.Add(new ServerMessage()
                         {
                             ChargeBoxId = chargeBoxId,
@@ -351,7 +354,7 @@ namespace EVCB_OCPP.WSServer
                     bool isNotSupported = session.SecWebSocketProtocol.Contains("ocpp1.6") ? false : true;
                     if (isNotSupported)
                     {
-                        logger.Debug(string.Format("ChargeBoxId:{0} SecWebSocketProtocol:{1} NotSupported", session.ChargeBoxId, session.SecWebSocketProtocol));
+                        //logger.Debug(string.Format("ChargeBoxId:{0} SecWebSocketProtocol:{1} NotSupported", session.ChargeBoxId, session.SecWebSocketProtocol));
                         WriteMachineLog(session, string.Format("SecWebSocketProtocol:{0} NotSupported", session.SecWebSocketProtocol), "Connection", "");
                         return;
                     }
@@ -368,7 +371,7 @@ namespace EVCB_OCPP.WSServer
 
                     clientDic.Add(session.ChargeBoxId, session);
                     session.m_ReceiveData += new ClientData.OCPPClientDataEventHandler<ClientData, String>(ReceivedMessage);
-                    logger.Debug("------------New " + (session == null ? "Oops" : session.ChargeBoxId));
+                   // logger.Debug("------------New " + (session == null ? "Oops" : session.ChargeBoxId));
                     WriteMachineLog(session, "NewSessionConnected", "Connection", "");
 
                     using (var db = new MainDBContext())
@@ -395,7 +398,7 @@ namespace EVCB_OCPP.WSServer
 
         private void ReceivedMessage(ClientData session, string rawdata)
         {
-           
+
             BasicMessageHandler msgAnalyser = new BasicMessageHandler();
             MessageResult analysisResult = msgAnalyser.AnalysisReceiveData(session, rawdata);
 
@@ -465,6 +468,8 @@ namespace EVCB_OCPP.WSServer
 
         }
 
+
+
         private void ProcessRequestMessage(MessageResult analysisResult, ClientData session, Actions action)
         {
             BasicMessageHandler msgAnalyser = new BasicMessageHandler();
@@ -519,6 +524,76 @@ namespace EVCB_OCPP.WSServer
                                 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":
@@ -1056,14 +1131,14 @@ namespace EVCB_OCPP.WSServer
 
                     if (clientDic.ContainsKey(session.ChargeBoxId))
                     {
-                        if(clientDic[session.ChargeBoxId].SessionID == session.SessionID)
+                        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);
                         }
-                     
+
                     }
                 }
             }
@@ -1083,13 +1158,13 @@ namespace EVCB_OCPP.WSServer
         {
             try
             {
-                
+
                 if (clientData == null || string.IsNullOrEmpty(data)) return;
                 using (var db = new ConnectionLogDBContext())
                 {
                     string sp = "[dbo].[uspInsertMachineConnectionLog] @CreatedOn," +
                           "@ChargeBoxId,@MessageType,@Data,@Msg,@IsSent,@EVSEEndPoint,@Session";
-                    var dd = DateTime.Now;
+                    var dd = DateTime.UtcNow;
                     SqlParameter[] parameter =
                     {
                       new SqlParameter("CreatedOn",dd),

+ 368 - 0
EVCB_OCPP.WSServer/Service/LoadingBalanceService.cs

@@ -0,0 +1,368 @@
+using Dapper;
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Data.SqlClient;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EVCB_OCPP.WSServer.Service
+{
+    public class LoadBalanceSetting
+    {
+        public int StationId { set; get; }
+
+        public int LBMode { set; get; }
+
+        public int LBCurrent { set; get; }
+
+    }
+
+    public class LoadingBalanceService
+    {
+        string mainConnectionString = ConfigurationManager.ConnectionStrings["MainDBContext"].ConnectionString;
+        string webConnectionString = ConfigurationManager.ConnectionStrings["WebDBContext"].ConnectionString;
+
+        public LoadingBalanceService()
+        {
+
+        }
+
+        public int GetStationIdByMachineId(string machineId)
+        {
+            int stationId = 0;
+            using (SqlConnection conn = new SqlConnection(webConnectionString))
+            {
+                var parameters = new DynamicParameters();
+                parameters.Add("@MachineId", machineId, DbType.String, ParameterDirection.Input);
+                string strSql = "Select StationId from [dbo].[StationMachine] where MachineId=@MachineId ; ";
+                stationId = conn.ExecuteScalar<Int32>(strSql, parameters);
+            }
+            return stationId;
+        }
+
+
+        public bool IsNeedtoCancelSetting(int stationId, string machineId, string chargeBoxId)
+        {
+            var setting = GetLoadBalance(stationId);
+            if (setting == null) return false;
+
+            if (setting.LBMode > 0 && setting.LBMode < 3 && !IsStillInTransactions(chargeBoxId))
+            {
+                // renew table
+                UpdateLoadbalanceRecord(stationId, machineId, 0, DateTime.UtcNow);
+                return true;
+
+            }
+
+            if (setting.LBMode >= 3 || setting.LBMode < 1)
+            {
+                CloseLoadbalanceRecord(stationId);
+               
+            }
+
+
+            return false;
+
+        }
+        private void CloseLoadbalanceRecord(int stationId)
+        {
+            using (SqlConnection conn = new SqlConnection(mainConnectionString))
+            {
+
+                var parameters = new DynamicParameters();
+                parameters.Add("@StationId", stationId, DbType.Int32, ParameterDirection.Input);
+                parameters.Add("@FinishedOn", DateTime.UtcNow, DbType.DateTime, ParameterDirection.Input);
+                string strSql = "Update  [dbo].[LoadingBalance]  SET FinishedOn=@FinishedOn where StationId=@StationId and FinishedOn='1991/01/01'; ";
+                conn.Execute(strSql, parameters);
+
+            }
+        }
+
+
+        private void UpdateLoadbalanceRecord(int stationId, string machineId, decimal power, DateTime? finishedOn, bool keepgoing = false)
+        {
+            using (SqlConnection conn = new SqlConnection(mainConnectionString))
+            {
+                if (finishedOn.HasValue)
+                {
+                    var parameters = new DynamicParameters();
+                    parameters.Add("@MachineId", machineId, DbType.String, ParameterDirection.Input);
+                    parameters.Add("@FinishedOn", finishedOn.Value, DbType.DateTime, ParameterDirection.Input);
+                    string strSql = "Update  [dbo].[LoadingBalance]  SET FinishedOn=@FinishedOn where MachineId=@MachineId and FinishedOn='1991/01/01'; ";
+                    conn.Execute(strSql, parameters);
+                }
+                else
+                {
+                    if (keepgoing)
+                    {
+                        var parameters = new DynamicParameters();
+                        parameters.Add("@MachineId", machineId, DbType.String, ParameterDirection.Input);
+                        parameters.Add("@Power", power, DbType.Decimal, ParameterDirection.Input);
+                        string strSql = "Update  [dbo].[LoadingBalance]  SET Power=@Power where MachineId=@MachineId and FinishedOn='1991/01/01'; ";
+                        conn.Execute(strSql, parameters);
+                    }
+                    else
+                    {
+                        var parameters = new DynamicParameters();
+                        parameters.Add("@StationId", stationId, DbType.Int32, ParameterDirection.Input);
+                        parameters.Add("@MachineId", machineId, DbType.String, ParameterDirection.Input);
+                        parameters.Add("@Power", power, DbType.Decimal, ParameterDirection.Input);
+                        parameters.Add("@CreatedOn", DateTime.UtcNow, DbType.DateTime, ParameterDirection.Input);
+                        parameters.Add("@FinishedOn", new DateTime(1991, 1, 1, 0, 0, 0, DateTimeKind.Utc), DbType.DateTime, ParameterDirection.Input);
+
+                        string strSql = "INSERT INTO [dbo].[LoadingBalance] " +
+                         "([StationId],[MachineId],[Power],[CreatedOn],[FinishedOn]) " +
+                         "VALUES(@StationId,@MachineId,@Power,@CreatedOn,@FinishedOn);";
+
+                        conn.Execute(strSql, parameters);
+                    }
+
+                }
+
+            }
+        }
+
+
+        private bool IsStillInTransactions(string chargeBoxId)
+        {
+            bool result = false;
+
+            using (SqlConnection conn = new SqlConnection(mainConnectionString))
+            {
+                var parameters = new DynamicParameters();
+                parameters.Add("@ChargeBoxId", chargeBoxId, DbType.String, ParameterDirection.Input);
+                string strSql = "Select count(*) from [dbo].[TransactionRecord] where ChargeBoxId=@ChargeBoxId and StopTime='1991/01/01'; ";
+                result = conn.ExecuteScalar<bool>(strSql, parameters);
+            }
+
+            return result;
+        }
+
+        private decimal? GetCurrentSetting(string machineId)
+        {
+            decimal? result = (decimal?)null;
+
+            using (SqlConnection conn = new SqlConnection(mainConnectionString))
+            {
+                var parameters = new DynamicParameters();
+                parameters.Add("@MachineId", machineId, DbType.String, ParameterDirection.Input);
+                string strSql = "Select Power from [dbo].[LoadingBalance] where MachineId=@MachineId and FinishedOn='1991/01/01'; ";
+                result = conn.ExecuteScalar<decimal>(strSql, parameters);
+            }
+
+            return result;
+        }
+
+
+
+        public Dictionary<string, decimal?> GetRerangeSettingPower(int stationId)
+        {
+            Dictionary<string, decimal?> dic = new Dictionary<string, decimal?>();
+            var setting = GetLoadBalance(stationId);
+            if (setting == null) return null;
+
+            if (setting != null && setting.LBMode == 2)
+            {
+                string machineId = string.Empty;
+                decimal ratedPower = GetRatedPower(machineId);
+                //找站內最早要充電的交易 下發充電Power & 填寫新給的Power
+                using (SqlConnection conn = new SqlConnection(mainConnectionString))
+                {
+                    var parameters = new DynamicParameters();
+                    parameters.Add("@StationId", stationId, DbType.Int32, ParameterDirection.Input);
+                    string strSql = "Select M.Id from [dbo].[LoadingBalance] LB,  [dbo].[Machine] M  where LB.StationId=@StationId and  LB.MachineId=M.Id and LB.Power < M.RatedPower and LB.FinishedOn='1991/01/01' order by LB.Id asc; ";
+                    machineId = conn.ExecuteScalar<string>(strSql, parameters);
+                }
+
+                if (!string.IsNullOrEmpty(machineId))
+                {
+                    decimal estimatedPwerValue = GetFCFSPower(stationId, machineId, setting.LBCurrent);
+
+                    // renew table
+                    UpdateLoadbalanceRecord(stationId, machineId, estimatedPwerValue, null, true);
+                   // UpdateLoadbalanceRecord(stationId, machineId, estimatedPwerValue, null);
+
+                    dic.Add(machineId, estimatedPwerValue);
+                }
+
+
+            }
+
+            if (setting != null && setting.LBMode == 1)
+            {
+                dic = GetAveragePower(stationId, setting.LBCurrent);
+                foreach (var kv in dic)
+                {
+                    if (kv.Value.HasValue)
+                    {
+                        UpdateLoadbalanceRecord(stationId, kv.Key, 0, DateTime.UtcNow);
+                        UpdateLoadbalanceRecord(stationId, kv.Key, kv.Value.Value, null);
+                    }
+
+                }
+            }
+
+            return dic;
+
+        }
+
+        public Dictionary<string, decimal?> GetSettingPower(int stationId, string machineId)
+        {
+            Dictionary<string, decimal?> dic = new Dictionary<string, decimal?>();
+            var setting = GetLoadBalance(stationId);
+            if (setting == null) return null;
+
+            if (setting != null)
+            {
+                if (setting.LBMode == 1)
+                {
+                    dic = GetAveragePower(stationId, setting.LBCurrent, machineId);
+                    foreach (var kv in dic)
+                    {
+                        if (kv.Value.HasValue)
+                        {
+                            UpdateLoadbalanceRecord(stationId, kv.Key, 0, DateTime.UtcNow);
+                            UpdateLoadbalanceRecord(stationId, kv.Key, kv.Value.Value, null);
+                        }
+
+                    }
+                }
+                else if (setting.LBMode == 2)
+                {
+                    dic.Add(machineId, GetFCFSPower(stationId, machineId, setting.LBCurrent));
+
+                    UpdateLoadbalanceRecord(stationId, machineId, 0, DateTime.UtcNow);
+                    UpdateLoadbalanceRecord(stationId, machineId, dic[machineId].Value, null);
+
+                }
+                else
+                {
+                    // 把LB TABLE 關閉
+                    CloseLoadbalanceRecord(stationId);
+
+                }
+            }
+
+            return dic;
+        }
+
+
+        public LoadBalanceSetting GetLoadBalance(int stationId)
+        {
+            LoadBalanceSetting setting = null;
+            using (SqlConnection conn = new SqlConnection(webConnectionString))
+            {
+                var parameters = new DynamicParameters();
+                parameters.Add("@StationId", stationId, DbType.Int32, ParameterDirection.Input);
+
+                string strSql = "Select LBMode,LBCurrent from [dbo].[Station] where Id=@StationId ; ";
+                setting = conn.Query<LoadBalanceSetting>(strSql, parameters).FirstOrDefault();
+            }
+            return setting;
+        }
+
+        private List<string> GetIdsbyStationId(int stationId)
+        {
+            List<string> machineIds = new List<string>();
+            using (SqlConnection conn = new SqlConnection(webConnectionString))
+            {
+                var parameters = new DynamicParameters();
+                parameters.Add("@StationId", stationId, DbType.Int16, ParameterDirection.Input);
+                string strSql = "Select MachineId from [dbo].[StationMachine] where StationId=@StationId; ";
+                machineIds = conn.Query<String>(strSql, parameters).ToList();
+            }
+            return machineIds;
+        }
+
+
+
+        private Dictionary<string, decimal?> GetAveragePower(int stationId, int availableCapacity, string machineId = "")
+        {
+            Dictionary<string, decimal?> dic = new Dictionary<string, decimal?>();
+            //總量 * 該樁的額定功率/該站充電中樁的總額定功率
+            List<string> _MachineIds = new List<string>();
+            int skipCount = 0;
+            int size = 200;
+            int takeCount = 0;
+            int totalRatePower = 0;
+
+            using (SqlConnection conn = new SqlConnection(mainConnectionString))
+            {
+                var parameters = new DynamicParameters();
+                parameters.Add("@StationId", stationId, DbType.Int32, ParameterDirection.Input);
+                string strSql = "Select MachineId from [dbo].[LoadingBalance] where StationId=@StationId and FinishedOn='1991/01/01'; ";
+                _MachineIds = conn.Query<string>(strSql, parameters).ToList();
+            }
+
+            if (!string.IsNullOrEmpty(machineId) && !_MachineIds.Contains(machineId))
+            {
+                _MachineIds.Add(machineId);
+            }
+
+            while (skipCount < _MachineIds.Count())
+            {
+                takeCount = _MachineIds.Count() - skipCount > size ? size : _MachineIds.Count() - skipCount;
+
+                using (SqlConnection conn = new SqlConnection(mainConnectionString))
+                {
+                    string strSql = "Select Sum(RatedPower) from [dbo].[Machine] where Id in @machineIds and [Online]=1; ";
+                    totalRatePower += conn.ExecuteScalar<Int32>(strSql, new { machineIds = _MachineIds.ToArray() });
+                    skipCount += takeCount;
+                }
+            }
+
+            foreach (var id in _MachineIds)
+            {
+                int singleRatePower = (int)GetRatedPower(id);
+                var value = totalRatePower == 0 ? 0 : availableCapacity * singleRatePower / totalRatePower;
+                dic.Add(id, value);
+            }
+
+            return dic;
+
+        }
+
+        private decimal GetRatedPower(string machineId)
+        {
+            decimal ratedPower = 0;
+            using (SqlConnection conn = new SqlConnection(mainConnectionString))
+            {
+                var parameters = new DynamicParameters();
+                parameters.Add("@machineId", machineId, DbType.String, ParameterDirection.Input);
+                string strSql = "Select RatedPower from [dbo].[Machine] where Id=@machineId; ";
+                ratedPower = conn.ExecuteScalar<Int32>(strSql, parameters);
+            }
+            return ratedPower;
+        }
+
+        private decimal GetFCFSPower(int stationId, string machineId, int availableCapacity)
+        {
+
+            decimal ongoingPower = 0;
+            decimal singleRatePower = GetRatedPower(machineId);
+
+            //先找LB 裡面目前下發的Power
+            decimal? currentPower = GetCurrentSetting(machineId);
+
+            if (!currentPower.HasValue) currentPower = 0;
+
+            //總量 - 所有正在進行的Power
+            using (SqlConnection conn = new SqlConnection(mainConnectionString))
+            {
+                var parameters = new DynamicParameters();
+                parameters.Add("@StationId", stationId, DbType.Int32, ParameterDirection.Input);
+                string strSql = "Select Sum(Power) from [dbo].[LoadingBalance] where StationId=@StationId and FinishedOn='1991/01/01'; ";
+                ongoingPower = conn.ExecuteScalar<Int32>(strSql, parameters);
+            }
+
+            return availableCapacity - (ongoingPower - currentPower.Value) > singleRatePower ? singleRatePower :
+                (availableCapacity - (ongoingPower - currentPower.Value) > 0 ? availableCapacity - (ongoingPower - currentPower.Value) : 0);
+        }
+
+
+    }
+}
+

+ 4 - 1
EVCB_OCPP.WSServer/SuperSocket.Protocol/ClientData.cs

@@ -19,6 +19,8 @@ namespace OCPPServer.Protocol
 
         public Guid CustomerId { get; set; }
 
+        public string MachineId { set; get; }
+
         public string CustomerName { get; set; }
 
         public delegate void OCPPClientDataEventHandler<ClientData, String>(ClientData clientdata, String msg);
@@ -29,10 +31,11 @@ namespace OCPPServer.Protocol
         {
             IsCheckIn = false;
             ChargeBoxId = SessionID;
+            MachineId = SessionID;
 
         }
 
-
+         
 
         /// <summary>
         /// Sends the raw binary data to client.

+ 4 - 3
EVCB_OCPP.WSServer/SuperSocket.Protocol/OCPPWSServer.cs

@@ -54,7 +54,7 @@ namespace OCPPServer.Protocol
 
         protected override bool ValidateClientCertificate(ClientData session, object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
         {
-            Console.WriteLine(string.Format("{0} :{1}", session.ChargeBoxId + " ValidateClientCertificate", sslPolicyErrors));
+          //  Console.WriteLine(string.Format("{0} :{1}", session.ChargeBoxId + " ValidateClientCertificate", sslPolicyErrors));
             return true;
             // return base.ValidateClientCertificate(session, sender, certificate, chain, sslPolicyErrors);
         }
@@ -63,12 +63,13 @@ namespace OCPPServer.Protocol
         {
             string[] words = session.Path.Split('/');
             session.ChargeBoxId = words.Last();
-            Console.WriteLine(string.Format("{0} :ValidateHandshake: {1}", DateTime.Now.ToString("yy/MM/dd HH:mm:ss.fff"), session.Path));
+          //  Console.WriteLine(string.Format("{0} :ValidateHandshake: {1}", DateTime.Now.ToString("yy/MM/dd HH:mm:ss.fff"), session.Path));
             bool isExistedSN = false;
             using (var db = new MainDBContext())
             {
                 var machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault();
                 session.CustomerId = machine == null ? Guid.Empty : machine.CustomerId;
+                session.MachineId = machine == null ? String.Empty : machine.Id;
                 isExistedSN = machine == null ? false : true;
             }
             if (!isExistedSN)
@@ -86,7 +87,7 @@ namespace OCPPServer.Protocol
 
                 return false;
             }
-          
+
 
             return true;
         }

+ 1 - 0
EVCB_OCPP.WSServer/packages.config

@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
+  <package id="Dapper" version="2.0.30" targetFramework="net471" />
   <package id="EntityFramework" version="6.2.0" targetFramework="net471" />
   <package id="log4net" version="2.0.3" targetFramework="net471" />
   <package id="Microsoft.Bcl.AsyncInterfaces" version="1.1.0" targetFramework="net471" />

+ 25 - 15
SuperWebSocket/WebSocketServer.cs

@@ -79,7 +79,7 @@ namespace SuperWebSocket
 
         }
 
-   
+
     }
 
     /// <summary>
@@ -129,7 +129,7 @@ namespace SuperWebSocket
         public WebSocketServer(ISubProtocol<TWebSocketSession> subProtocol)
             : this(new List<ISubProtocol<TWebSocketSession>> { subProtocol })
         {
-            
+
         }
 
         /// <summary>
@@ -224,7 +224,7 @@ namespace SuperWebSocket
         {
             if (m_SubProtocols.ContainsKey(subProtocol.Name))
             {
-                if(Logger.IsErrorEnabled)
+                if (Logger.IsErrorEnabled)
                     Logger.ErrorFormat("Cannot register duplicate name sub protocol! Duplicate name: {0}.", subProtocol.Name);
                 return false;
             }
@@ -246,7 +246,7 @@ namespace SuperWebSocket
                 {
                     string originalProtocolName = protocolConfig.Name;
                     string protocolName;
-                    
+
                     ISubProtocol<TWebSocketSession> subProtocolInstance;
 
                     if (!string.IsNullOrEmpty(originalProtocolName))
@@ -285,7 +285,7 @@ namespace SuperWebSocket
 
                         if (!string.IsNullOrEmpty(protocolConfig.Type))
                         {
-                            if(Logger.IsErrorEnabled)
+                            if (Logger.IsErrorEnabled)
                                 Logger.Error("You needn't set Type attribute for SubProtocol, if you don't set Name attribute!");
                             return false;
                         }
@@ -294,7 +294,7 @@ namespace SuperWebSocket
                     subProtocolConfigDict[protocolName] = protocolConfig;
                 }
 
-                if(subProtocolConfigDict.Values.Any())
+                if (subProtocolConfigDict.Values.Any())
                     m_SubProtocolConfigured = true;
             }
 
@@ -330,7 +330,7 @@ namespace SuperWebSocket
                     return false;
                 }
             }
-            
+
             return true;
         }
 
@@ -455,7 +455,7 @@ namespace SuperWebSocket
             }
             catch (Exception e)
             {
-                if(Logger.IsErrorEnabled)
+                if (Logger.IsErrorEnabled)
                     Logger.Error(e);
             }
             finally
@@ -489,7 +489,7 @@ namespace SuperWebSocket
         /// <exception cref="System.NotSupportedException"></exception>
         [Browsable(false)]
         [EditorBrowsable(EditorBrowsableState.Never)]
-        public override event RequestHandler<TWebSocketSession,IWebSocketFragment> NewRequestReceived
+        public override event RequestHandler<TWebSocketSession, IWebSocketFragment> NewRequestReceived
         {
             add { throw new NotSupportedException("Please use NewMessageReceived instead!"); }
             remove { throw new NotSupportedException("Please use NewMessageReceived instead!"); }
@@ -530,14 +530,24 @@ namespace SuperWebSocket
 
         internal void OnNewMessageReceived(TWebSocketSession session, string message)
         {
-            if (m_NewMessageReceived == null)
+            try
             {
-                ExecuteMessage(session, message);
+                if (m_NewMessageReceived == null)
+                {
+                    ExecuteMessage(session, message);
+                }
+                else
+                {
+                    m_NewMessageReceived(session, message);
+                }
             }
-            else
+            catch (Exception ex)
             {
-                m_NewMessageReceived(session, message);
+                if (Logger.IsErrorEnabled)
+                    Logger.Error(message + " " + ex.ToString());
             }
+
+
         }
 
         private SessionHandler<TWebSocketSession, byte[]> m_NewDataReceived;
@@ -654,7 +664,7 @@ namespace SuperWebSocket
             var commands = new List<ICommand<TWebSocketSession, IWebSocketFragment>>
                 {
                     new HandShake<TWebSocketSession>(),
-                    new Text<TWebSocketSession>(),  
+                    new Text<TWebSocketSession>(),
                     new Binary<TWebSocketSession>(),
                     new Close<TWebSocketSession>(),
                     new Ping<TWebSocketSession>(),
@@ -696,7 +706,7 @@ namespace SuperWebSocket
                 session.CurrentCommand = requestInfo.Key;
                 subCommand.ExecuteCommand(session, requestInfo);
                 session.PrevCommand = requestInfo.Key;
-                
+
 
                 if (Config.LogCommand && Logger.IsInfoEnabled)
                     Logger.Info(session, string.Format("Command - {0} - {1}", session.SessionID, requestInfo.Key));

+ 33 - 9
TestTool.RemoteTriggerAPP/MainWindow.xaml.cs

@@ -186,15 +186,39 @@ namespace TestTool.RemoteTriggerAPP
                     break;
                 case "SetChargingProfile":
                     {
-                        var chargingProfile = VerifyChargingProfile(chargingProfilePath);
-                        if (chargingProfile != null)
+                        //var chargingProfile = VerifyChargingProfile(chargingProfilePath);
+                        //if (chargingProfile != null)
+                        //{
+                        //    SetChargingProfile(chargingProfile);
+                        //}
+                        //else
+                        //{
+                        //    uxMsgTb.Text = "Please check chargingProfile.json exist in " + AppDomain.CurrentDomain.BaseDirectory;
+                        //}
+
+                        SetChargingProfile(new SetChargingProfileRequest()
                         {
-                            SetChargingProfile(chargingProfile);
-                        }
-                        else
-                        {
-                            uxMsgTb.Text = "Please check chargingProfile.json exist in " + AppDomain.CurrentDomain.BaseDirectory;
-                        }
+                            connectorId = 0,
+                            csChargingProfiles = new csChargingProfiles()
+                            {
+                                chargingProfileId = 1,
+                                chargingProfileKind = ChargingProfileKindType.Recurring,
+                                chargingProfilePurpose = ChargingProfilePurposeType.ChargePointMaxProfile,
+                                chargingSchedule = new ChargingSchedule()
+                                {
+                                    chargingRateUnit = ChargingRateUnitType.W,
+                                    chargingSchedulePeriod = new List<ChargingSchedulePeriod>()
+                                                    {
+                                                        new ChargingSchedulePeriod(){  startPeriod=0, limit=int.Parse(uxConfigValueTb.Text)}
+                                                    },
+                                  
+
+                                },
+                                recurrencyKind = RecurrencyKindType.Daily,
+                                stackLevel = 1,
+
+                            }
+                        });
 
                     }
                     break;
@@ -440,7 +464,7 @@ namespace TestTool.RemoteTriggerAPP
 
                 request.localAuthorizationList.Add(new AuthorizationData()
                 {
-                    idTag="F5902677",
+                    idTag = "F5902677",
                     idTagInfo = new IdTagInfo()
                     {
                         parentIdTag = "0000000000000000001",