9 Коміти 0bc54e37b1 ... 2624426b73

Автор SHA1 Опис Дата
  Jessica Tseng 2624426b73 更新BootNotification 邏輯 2 роки тому
  Jessica Tseng 2d3a9cd13b 顯示當下被拒絕的名單 2 роки тому
  Jessica Tseng 8d29f79499 1. 加入偵測拒絕連線機種名單功能(每五分鐘一次) 2 роки тому
  Jessica Tseng 7b6fbe524d 1.因應 CDFA 規格 ,停車費顯示資訊調整 加入XX hours XX minutes 2 роки тому
  Jessica Tseng 0c503b3e8a 1. LoadingBalance 邏輯調整,只有手動模式和平均模式,平均模式會除1.05 約 站點契約容量的95% 2 роки тому
  Jessica Tseng 9c6118c277 修改Stop Reason Reciept 顯示格式 again 2 роки тому
  Jessica Tseng 0176f4c3cc 修改Stop Reason Reciept 顯示格式' 2 роки тому
  Jessica Tseng 36f148a75a 依照 CDFA 認證規則調整Reciept 顯示格式 2 роки тому
  Jessica Tseng db5434d1ac FinalCost Receipt 因應CDFA 要求加入StopReason 2 роки тому

+ 25 - 0
EVCB_OCPP.WSServer/Dto/StationInfoDto.cs

@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EVCB_OCPP.WSServer.Dto
+{
+    public class StationInfoDto
+    {
+
+        public int Id { set; get; }
+
+        /// <summary>
+        /// LoadingBalance Mode
+        /// 0:None 1: Average
+        /// 2:FCFS 3:Manual
+        /// </summary>
+        public int LBMode { set; get; }
+
+        public int Availability { set; get; }
+
+
+    }
+}

+ 0 - 18
EVCB_OCPP.WSServer/Dto/TCCStationInfoDto.cs

@@ -1,18 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace EVCB_OCPP.WSServer.Dto
-{
-    public class TCCStationInfoDto
-    {
-        public decimal Lat { set; get; }
-
-        public decimal Long { set; get; }
-
-        public string ZipCode { set; get; }
-
-    }
-}

+ 0 - 16
EVCB_OCPP.WSServer/Dto/TCCWeatherDto.cs

@@ -1,16 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace EVCB_OCPP.WSServer.Dto
-{
-    public class TCCWeatherDto
-    {
-        public int WeatherID { set; get; }
-
-
-        public int Temperature { set; get; }
-    }
-}

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

@@ -151,9 +151,8 @@
     <Compile Include="Dto\IdTokenInfo.cs" />
     <Compile Include="Dto\ID_GetTxUserInfo.cs" />
     <Compile Include="Dto\StationFee.cs" />
-    <Compile Include="Dto\TCCWeatherDto.cs" />
+    <Compile Include="Dto\StationInfoDto.cs" />
     <Compile Include="Dto\TransactionEnergy.cs" />
-    <Compile Include="Dto\TCCStationInfoDto.cs" />
     <Compile Include="Message\OCPP16MessageHandler.cs" />
     <Compile Include="Message\OCPP20MessageHandler.cs" />
     <Compile Include="Message\SecurityProfileHandler.cs" />

+ 2 - 0
EVCB_OCPP.WSServer/GlobalConfig.cs

@@ -15,6 +15,8 @@ namespace EVCB_OCPP.WSServer
             "OCPP20_WSSUrl"
         };
 
+        public static List<string> DenyModelNames = new List<string>();
+
         public static  string UTC_DATETIMEFORMAT = "yyyy-MM-dd'T'HH':'mm':'ss'Z'";
 
         public static string TCC_API_URL = string.Empty;

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

@@ -68,7 +68,7 @@ namespace EVCB_OCPP.WSServer.Message
         static private ILogger logger = NLog.LogManager.GetCurrentClassLogger();
         string webConnectionString = ConfigurationManager.ConnectionStrings["WebDBContext"].ConnectionString;
         private OuterHttpClient httpClient = new OuterHttpClient();
-     
+
         async internal Task<MessageResult> ExecuteCoreRequest(Actions action, ClientData session, IRequest request)
         {
             Stopwatch watch = new Stopwatch();
@@ -201,9 +201,20 @@ namespace EVCB_OCPP.WSServer.Message
                                     int.TryParse(configVaule, out heartbeat_interval);
                                 }
                             }
-                            var confirm = new BootNotificationConfirmation() { currentTime = DateTime.UtcNow, interval = session.IsPending ? heartbeat_interval : 5, status = session.IsPending ? Packet.Messages.SubTypes.RegistrationStatus.Accepted : RegistrationStatus.Pending };
+                            if (session.IsPending == true)
+                            {
+                                session.IsPending = false;
+                            }
+                            if (session.IsPending == null)
+                            {
+                                session.IsPending = true;
+                            }
+                          
+                            var confirm = new BootNotificationConfirmation() { currentTime = DateTime.UtcNow, interval = session.IsPending.Value ? 5:heartbeat_interval , status = session.IsPending.Value ?RegistrationStatus.Pending : RegistrationStatus.Accepted };
+
 
-                            session.IsPending = !session.IsPending;
+                          
+                           
                             result.Message = confirm;
                             result.Success = true;
                         }
@@ -574,7 +585,7 @@ namespace EVCB_OCPP.WSServer.Message
                                 _idTagInfo = new IdTagInfo() { expiryDate = DateTime.UtcNow.AddDays(1), status = AuthorizationStatus.Accepted };
                             }
                             try
-                            {                              
+                            {
                                 using (var db = new MainDBContext())
                                 {
                                     var transaction = db.TransactionRecord.Where(x => x.Id == _request.transactionId
@@ -975,14 +986,14 @@ namespace EVCB_OCPP.WSServer.Message
                                                 if (bill.Count == 1)
                                                 {
                                                     confirmbill = bill;
-                                                    receipt += string.Format("| {0} - {1}:| {2} kWh @ ${3}/kWh=${4}", tx.StartTime.ToString("hh:mm tt", new CultureInfo("en-us")), tx.StopTime.ToString("hh:mm tt", new CultureInfo("en-us")),
+                                                    receipt += string.Format("| {0} - {1}:| {2} kWh @ ${3}/kWh= ${4}", tx.StartTime.ToString("hh:mm tt", new CultureInfo("en-us")), tx.StopTime.ToString("hh:mm tt", new CultureInfo("en-us")),
                                                         confirmbill[0].PeriodEnergy.ToString("0.0000"), bill[0].Fee, bill[0].Total);
 
                                                     break;
                                                 }
                                                 if (bill.Count == 0)
                                                 {
-                                                    receipt += string.Format("| {0} - {1} @ ${2}/hr=${3}", feedto.StartTime.ToString("hh:mm tt", new CultureInfo("en-us")),
+                                                    receipt += string.Format("| {0} - {1} @ ${2}/hr= ${3}", feedto.StartTime.ToString("hh:mm tt", new CultureInfo("en-us")),
                                                        feedto.StopTime.ToString("hh:mm tt", new CultureInfo("en-us")), feedto.Fee.Split('|')[0], chargingCost);
 
                                                     break;
@@ -1009,7 +1020,7 @@ namespace EVCB_OCPP.WSServer.Message
                                                         }
 
                                                     }
-                                                    receipt += string.Format("| {0} - {1}:| {2} kWh @ ${3}/kWh=${4}", confirmbill[confirmbill.Count - 1].StartTime, confirmbill[confirmbill.Count - 1].EndTime,
+                                                    receipt += string.Format("| {0} - {1}:| {2} kWh @ ${3}/kWh= ${4}", confirmbill[confirmbill.Count - 1].StartTime, confirmbill[confirmbill.Count - 1].EndTime,
                                                         confirmbill[confirmbill.Count - 1].PeriodEnergy.ToString("0.0000"), confirmbill[confirmbill.Count - 1].Fee, confirmbill[confirmbill.Count - 1].Total);
 
                                                     if (confirmbill.Count == 24) break;
@@ -1019,25 +1030,14 @@ namespace EVCB_OCPP.WSServer.Message
 
                                             }
 
-                                            if (session.CustomerId == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8"))
-                                            {
-                                                chargingCost = confirmbill.Count > 0 ? confirmbill.Sum(x => x.Total) : chargingCost;
-                                                chargingCost = chargedEnergy == 0 ? 0 : (chargingCost + parkingCost < 1 ? 1 : chargingCost);  //台泥最低一元
-                                                receipt += string.Format("|Total Energy Fee : ${0}", chargingCost);
+                                            chargingCost = confirmbill.Count > 0 ? confirmbill.Sum(x => x.Total) : chargingCost;
+                                            receipt += string.Format("|Total Energy Fee : ${0}", chargingCost);
 
-                                                receipt += string.Format("|Parking Fee: | {0} - {1} @ ${2}/hr=${3}", feedto.StartTime.ToString("hh:mm tt", new CultureInfo("en-us")),
-                                                feedto.StopTime.ToString("hh:mm tt", new CultureInfo("en-us")), parkingFee, parkingCost);
-                                                tx.Cost = chargingCost + parkingCost;
-                                            }
-                                            else
-                                            {
-                                                chargingCost = confirmbill.Count > 0 ? confirmbill.Sum(x => x.Total) : chargingCost;
-                                                receipt += string.Format("|Total Energy Fee : ${0}", chargingCost);
+                                            receipt += string.Format("|Parking Fee: | {0} - {1}: | {2} @ ${3}/hr= ${4}", feedto.StartTime.ToString("hh:mm tt", new CultureInfo("en-us")),
+                                            feedto.StopTime.ToString("hh:mm tt", new CultureInfo("en-us")), (totalHours / 1 >= 1) ? string.Format("{0} hours {1} minutes", (int)totalHours / 1, ((totalHours % 1) * 60).ToString("0.0")) : string.Format("{0} minutes", ((totalHours % 1) * 60).ToString("0.0")), parkingFee, parkingCost);
+                                            receipt += string.Format("|Stop Reason: {0}", tx.StopReason);
 
-                                                receipt += string.Format("|Parking Fee: | {0} - {1} @ ${2}/hr=${3}", feedto.StartTime.ToString("hh:mm tt", new CultureInfo("en-us")),
-                                                feedto.StopTime.ToString("hh:mm tt", new CultureInfo("en-us")), parkingFee, parkingCost);
-                                                tx.Cost = chargingCost + parkingCost;
-                                            }
+                                            tx.Cost = chargingCost + parkingCost;
 
 
                                             if (customerInfo != null && customerInfo.InstantStopTxReport)

+ 11 - 14
EVCB_OCPP.WSServer/Message/FirmwareManagementProfileHandler.cs

@@ -77,6 +77,9 @@ namespace EVCB_OCPP.WSServer.Message
 
                                         db.SaveChanges();
 
+                                        var  clearMachine =  db.Machine.Where(x => x.Id == machine.Id).FirstOrDefault();
+                                        clearMachine.FW_AssignedVersion = null;
+                                        db.SaveChanges();
                                     }
 
                                 }
@@ -91,22 +94,16 @@ namespace EVCB_OCPP.WSServer.Message
                                     {
                                         item.EVSE_Status = (int)_request.status;
                                         item.FinishedOn = DateTime.UtcNow;
-                                        if (string.IsNullOrEmpty(item.EVSE_Value))
-                                        {
-                                            Console.WriteLine("怎麼悾悾的");
-                                        }
-
-                                        if (!string.IsNullOrEmpty(item.EVSE_Value) && _request.status == Packet.Messages.SubTypes.FirmwareStatus.Installed)
-                                        {
-                                            int version = 0;
-                                            int.TryParse(item.EVSE_Value.Split(':').Last(), out version);
-                                            var machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault();
-                                            machine.FW_VersionReport = version;
-                                        }
+                                       
+                                        //if (!string.IsNullOrEmpty(item.EVSE_Value) && _request.status == Packet.Messages.SubTypes.FirmwareStatus.Installed)
+                                        //{
+                                        //    int version = 0;
+                                        //    int.TryParse(item.EVSE_Value.Split(':').Last(), out version);
+                                        //    var machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault();
+                                        //    machine.FW_VersionReport = version;
+                                        //}
                                     }
 
-
-
                                     db.SaveChanges();
                                 }
                             }

+ 228 - 0
EVCB_OCPP.WSServer/Message/FirmwareManagementProfileHandler.cs.bak

@@ -0,0 +1,228 @@
+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.FirmwareManagement;
+using Newtonsoft.Json;
+using OCPPServer.Protocol;
+using System;
+using System.Data.Entity;
+using System.Linq;
+
+namespace EVCB_OCPP.WSServer.Message
+{
+    internal partial class ProfileHandler
+    {
+        internal MessageResult ExecuteFirmwareManagementRequest(Actions action, ClientData session, IRequest request)
+        {
+            MessageResult result = new MessageResult() { Success = false };
+            try
+            {
+                switch (action)
+                {
+
+                    case Actions.FirmwareStatusNotification:
+                        {
+                            FirmwareStatusNotificationRequest _request = request as FirmwareStatusNotificationRequest;
+
+                            if (_request.status == Packet.Messages.SubTypes.FirmwareStatus.Idle)
+                            {
+                                string requestId = Guid.NewGuid().ToString();
+                                using (var db = new MainDBContext())
+                                {
+                                    var machine = db.Machine.Where(x => x.FW_AssignedVersion.HasValue == true && x.FW_AssignedVersion.HasValue
+                                       && x.FW_AssignedVersion != x.FW_VersionReport && x.ChargeBoxId == session.ChargeBoxId)
+                                        .Select(x => new { x.Id, x.FW_AssignedVersion }).AsNoTracking().FirstOrDefault();
+
+                                    if (machine != null)
+                                    {
+                                        var mv = db.MachineVersionFile.Include(c => c.UploadFile)
+                                         .Where(c => c.Id == machine.FW_AssignedVersion.Value).First();
+
+                                        string downloadUrl = mv.UploadFile.FileUrl;
+
+                                        var _updateFWrequest = new UpdateFirmwareRequest()
+                                        {
+                                            location = new Uri(downloadUrl),
+                                            retries = 3,
+                                            retrieveDate = DateTime.UtcNow,
+                                            retryInterval = 10
+                                        };
+
+                                        db.MachineOperateRecord.Add(new MachineOperateRecord()
+                                        {
+                                            CreatedOn = DateTime.UtcNow,
+                                            ChargeBoxId = session.ChargeBoxId,
+                                            SerialNo = requestId,
+                                            RequestContent = JsonConvert.SerializeObject(_updateFWrequest, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                            EVSE_Status = 0,
+                                            EVSE_Value = "Fw Version:" + machine.FW_AssignedVersion,
+                                            Status = 0,
+                                            RequestType = 0,
+                                            Action = _updateFWrequest.Action.ToString()
+
+                                        });
+
+                                        db.ServerMessage.Add(new ServerMessage()
+                                        {
+                                            ChargeBoxId = session.ChargeBoxId,
+                                            CreatedBy = "Server",
+                                            CreatedOn = DateTime.UtcNow,
+                                            OutAction = _updateFWrequest.Action.ToString(),
+                                            OutRequest = JsonConvert.SerializeObject(_updateFWrequest, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                            SerialNo = requestId,
+                                            InMessage = string.Empty
+
+                                        });
+
+                                        db.SaveChanges();
+
+                                    }
+
+                                }
+                            }
+                            else
+                            {
+                                using (var db = new MainDBContext())
+                                {
+                                    var item = db.MachineOperateRecord.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.RequestType == 0)
+                                        .OrderByDescending(x => x.CreatedOn).FirstOrDefault();
+                                    if (item != null)
+                                    {
+                                        item.EVSE_Status = (int)_request.status;
+                                        item.FinishedOn = DateTime.UtcNow;
+                                        if (string.IsNullOrEmpty(item.EVSE_Value))
+                                        {
+                                            Console.WriteLine("怎麼悾悾的");
+                                        }
+
+                                        if (!string.IsNullOrEmpty(item.EVSE_Value) && _request.status == Packet.Messages.SubTypes.FirmwareStatus.Installed)
+                                        {
+                                            int version = 0;
+                                            int.TryParse(item.EVSE_Value.Split(':').Last(), out version);
+                                            var machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault();
+                                            machine.FW_VersionReport = version;
+                                        }
+                                    }
+
+
+
+                                    db.SaveChanges();
+                                }
+                            }
+
+                            var confirm = new FirmwareStatusNotificationConfirmation() { };
+
+                            result.Message = confirm;
+                            result.Success = true;
+                        }
+                        break;
+                    case Actions.DiagnosticsStatusNotification:
+                        {
+                            DiagnosticsStatusNotificationRequest _request = request as DiagnosticsStatusNotificationRequest;
+
+                            var confirm = new DiagnosticsStatusNotificationConfirmation() { };
+
+                            result.Message = confirm;
+                            result.Success = true;
+
+                        }
+                        break;
+
+                    default:
+                        {
+                            Console.WriteLine(string.Format("Not Implement {0} Logic", request.GetType().ToString().Replace("OCPPPackage.Messages.FirmwareManagement.", "")));
+                        }
+                        break;
+                }
+            }
+            catch (Exception ex)
+            {
+                logger.Fatal(string.Format("chargeBoxId:{0} {1}", session.ChargeBoxId, action));
+                logger.Fatal(string.Format("Data {0}", request.ToString()));
+                logger.Fatal(string.Format("Error {0}", ex.ToString()));
+                result.Exception = ex;
+            }
+            return result;
+        }
+
+        internal MessageResult ExecuteFirmwareManagementConfirm(Actions action, ClientData session, IConfirmation confirm, string requestId)
+        {
+            MessageResult result = new MessageResult() { Success = true };
+
+            switch (action)
+            {
+                case Actions.UpdateFirmware:
+                case Actions.GetDiagnostics:
+                    {
+                        string evse_rep = string.Empty;
+                        if (confirm is GetDiagnosticsConfirmation)
+                        {
+                            var confirmation = confirm as GetDiagnosticsConfirmation;
+                            evse_rep = confirmation.fileName;
+                        }
+                        using (var db = new MainDBContext())
+                        {
+                            var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                            x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                            if (operation != null)
+                            {
+                                operation.FinishedOn = DateTime.UtcNow;
+                                operation.Status = 1;//電樁有回覆
+                                operation.EVSE_Status = (int)1;//OK
+                                operation.EVSE_Value = string.IsNullOrEmpty(evse_rep) ? operation.EVSE_Value : evse_rep;
+                                db.SaveChanges();
+                            }
+
+                        }
+                    }
+                    break;
+                default:
+                    {
+                        Console.WriteLine(string.Format("Not Implement {0} Logic", confirm.GetType().ToString().Replace("OCPPPackage.Messages.FirmwareManagement.", "")));
+                    }
+                    break;
+            }
+            return result;
+        }
+
+
+        internal MessageResult ReceivedFirmwareManagementError(Actions action, string errorMsg, ClientData session, string requestId)
+        {
+            MessageResult result = new MessageResult() { Success = true };
+
+            switch (action)
+            {
+                case Actions.FirmwareStatusNotification:
+                case Actions.UpdateFirmware:
+                case Actions.GetDiagnostics:
+                case Actions.DiagnosticsStatusNotification:
+                    {
+                        using (var db = new MainDBContext())
+                        {
+                            var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                            x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                            if (operation != null)
+                            {
+                                operation.FinishedOn = DateTime.UtcNow;
+                                operation.Status = 1;//電樁有回覆
+                                operation.EVSE_Status = (int)255;//錯誤
+                                operation.EVSE_Value = errorMsg;
+                                db.SaveChanges();
+                            }
+
+                        }
+                    }
+                    break;
+
+                default:
+                    {
+                        Console.WriteLine(string.Format("Not Implement {0} Logic", action));
+                    }
+                    break;
+            }
+            return result;
+
+        }
+    }
+}

+ 5 - 4
EVCB_OCPP.WSServer/Message/SmartChargingProfileHandler.cs

@@ -22,6 +22,7 @@ namespace EVCB_OCPP.WSServer.Message
             {
                 var _setProfileRequest = new SetChargingProfileRequest()
                 {
+                    //   
                     connectorId = 0,
                     csChargingProfiles = new Packet.Messages.SubTypes.csChargingProfiles()
                     {
@@ -33,14 +34,14 @@ namespace EVCB_OCPP.WSServer.Message
                             chargingRateUnit = unit,
                             chargingSchedulePeriod = new List<Packet.Messages.SubTypes.ChargingSchedulePeriod>()
                                                     {
-                                                        new Packet.Messages.SubTypes.ChargingSchedulePeriod(){  startPeriod=0, limit=value*1000}
+                                                        new Packet.Messages.SubTypes.ChargingSchedulePeriod(){  startPeriod=0, limit=value }
                                                     },
-                            duration = 60,
-
+                            duration = 86400,
                         },
                         recurrencyKind = Packet.Messages.SubTypes.RecurrencyKindType.Daily,
                         stackLevel = 1,
 
+
                     }
                 };
 
@@ -51,7 +52,7 @@ namespace EVCB_OCPP.WSServer.Message
                     CreatedOn = DateTime.UtcNow,
                     OutAction = _setProfileRequest.Action.ToString(),
                     OutRequest = JsonConvert.SerializeObject(_setProfileRequest, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
-                    SerialNo = Guid.Empty.ToString(),
+                    SerialNo = Guid.NewGuid().ToString(),
                     InMessage = string.Empty
 
                 });

+ 208 - 0
EVCB_OCPP.WSServer/Message/SmartChargingProfileHandler.cs.bak

@@ -0,0 +1,208 @@
+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;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace EVCB_OCPP.WSServer.Message
+{
+    internal partial class ProfileHandler
+    {
+
+
+        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.UtcNow,
+                    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.UtcNow,
+                    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();
+            }
+        }
+
+
+
+
+
+        internal MessageResult ExecuteSmartChargingConfirm(Actions action, ClientData session, IConfirmation confirm, string requestId)
+        {
+            MessageResult result = new MessageResult() { Success = true };
+
+            switch (action)
+            {
+                case Actions.ClearChargingProfile:
+
+                    {
+                        ClearChargingProfileConfirmation _confirm = confirm as ClearChargingProfileConfirmation;
+                        ClearChargingProfileRequest _request = _confirm.GetRequest() as ClearChargingProfileRequest;
+                        using (var db = new MainDBContext())
+                        {
+                            var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                            x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                            if (operation != null)
+                            {
+                                operation.FinishedOn = DateTime.UtcNow;
+                                operation.Status = 1;//電樁有回覆
+                                operation.EVSE_Status = (int)_confirm.status;//OK
+                                operation.EVSE_Value = _confirm.status.ToString();
+                                db.SaveChanges();
+                            }
+
+                        }
+                    }
+                    break;
+                case Actions.SetChargingProfile:
+                    {
+                        SetChargingProfileConfirmation _confirm = confirm as SetChargingProfileConfirmation;
+                        SetChargingProfileRequest _request = _confirm.GetRequest() as SetChargingProfileRequest;
+                        using (var db = new MainDBContext())
+                        {
+                            var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                            x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                            if (operation != null)
+                            {
+                                operation.FinishedOn = DateTime.UtcNow;
+                                operation.Status = 1;//電樁有回覆
+                                operation.EVSE_Status = (int)_confirm.status;//OK
+                                operation.EVSE_Value = _confirm.status.ToString();
+                                db.SaveChanges();
+                            }
+
+                        }
+                    }
+                    break;
+                case Actions.GetCompositeSchedule:
+                    {
+                        GetCompositeScheduleConfirmation _confirm = confirm as GetCompositeScheduleConfirmation;
+                        GetCompositeScheduleRequest _request = _confirm.GetRequest() as GetCompositeScheduleRequest;
+                        using (var db = new MainDBContext())
+                        {
+                            var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                            x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                            if (operation != null)
+                            {
+                                operation.FinishedOn = DateTime.UtcNow;
+                                operation.Status = 1;//電樁有回覆
+                                operation.EVSE_Status = (int)_confirm.status;//OK
+                                operation.EVSE_Value = JsonConvert.SerializeObject(_confirm.chargingSchedule, Formatting.None);
+                                db.SaveChanges();
+                            }
+
+                        }
+                    }
+                    break;
+                default:
+                    {
+                        Console.WriteLine(string.Format("Not Implement {0} Logic", confirm.GetType().ToString().Replace("OCPPPackage.Messages.RemoteTrigger.", "")));
+                    }
+                    break;
+            }
+            return result;
+        }
+
+
+        internal MessageResult ReceivedSmartChargingError(Actions action, string errorMsg, ClientData session, string requestId)
+        {
+            MessageResult result = new MessageResult() { Success = true };
+
+            switch (action)
+            {
+                case Actions.ClearChargingProfile:
+                case Actions.SetChargingProfile:
+                case Actions.GetCompositeSchedule:
+                    {
+                        using (var db = new MainDBContext())
+                        {
+                            var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                            x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                            if (operation != null)
+                            {
+                                operation.FinishedOn = DateTime.UtcNow;
+                                operation.Status = 1;//電樁有回覆
+                                operation.EVSE_Status = (int)255;//錯誤
+                                operation.EVSE_Value = errorMsg;
+                                db.SaveChanges();
+                            }
+
+                        }
+                    }
+                    break;
+
+                default:
+                    {
+                        Console.WriteLine(string.Format("Not Implement {0} Logic", action));
+                    }
+                    break;
+            }
+            return result;
+
+        }
+    }
+}

+ 4 - 4
EVCB_OCPP.WSServer/Properties/AssemblyInfo.cs

@@ -31,8 +31,8 @@ using System.Runtime.InteropServices;
 //
 // 您可以指定所有的值,或將組建編號或修訂編號設為預設值
 // 指定為預設值: 
-// [assembly: AssemblyVersion("1.2.0.0")]
-[assembly: AssemblyVersion("1.2.0.0")]
-[assembly: AssemblyFileVersion("1.2.0.0")]
+// [assembly: AssemblyVersion("1.2.1.0")]
+[assembly: AssemblyVersion("1.2.1.0")]
+[assembly: AssemblyFileVersion("1.2.1.0")]
 
-[assembly: AssemblyInformationalVersion("92c630c")]
+[assembly: AssemblyInformationalVersion("2d3a9cd")]

+ 153 - 473
EVCB_OCPP.WSServer/ProtalServer.cs

@@ -49,6 +49,8 @@ namespace EVCB_OCPP.WSServer
     }
     internal class ProtalServer
     {
+
+        #region private fields
         static private ILogger logger = NLog.LogManager.GetCurrentClassLogger();
         private OuterHttpClient httpClient = new OuterHttpClient();
         private DateTime lastcheckdt = DateTime.UtcNow.AddSeconds(-20);
@@ -59,10 +61,10 @@ namespace EVCB_OCPP.WSServer
         private List<NeedConfirmMessage> needConfirmPacketList = new List<NeedConfirmMessage>();
         private DateTime checkUpdateDt = DateTime.UtcNow;
         private DateTime _CheckFeeDt = DateTime.UtcNow;
-        private DateTime _CheckWeatherDt = DateTime.UtcNow;
+        private DateTime _CheckLBDt = DateTime.UtcNow;
+        private DateTime _CheckDenyListDt = DateTime.UtcNow.AddDays(-1);
         private LoadingBalanceService _loadingBalanceService = new LoadingBalanceService();
-        private Dictionary<string, TCCWeatherDto> TCCStationDic = new Dictionary<string, TCCWeatherDto>();
-
+        private List<StationInfoDto> _StationInfo = new List<StationInfoDto>();
         private List<string> needConfirmActions = new List<string>()
         {
              "GetConfiguration",
@@ -98,28 +100,25 @@ namespace EVCB_OCPP.WSServer
         };
         private CancellationTokenSource _cts = new CancellationTokenSource();
         private CancellationToken _ct;
-        private string _ocpp20NetworkSetting = "";
+        private string webConnectionString = ConfigurationManager.ConnectionStrings["WebDBContext"].ConnectionString;
+
+        #endregion
+
 
         internal ProtalServer()
         {
             _ct = _cts.Token;
             WarmUpLog();
-
-
-
-
+            DenyModelCheckTrigger(true);
         }
 
-
         internal void Start()
         {
-
             if (!GlobalConfig.LoadAPPConfig())
             {
                 Console.WriteLine("Please check App.Config setting .");
                 return;
             }
-            //ReadTCCSetting();
             OpenNetwork();
 
             Task serverCommandTask = new Task(ServerMessageTrigger, _ct);
@@ -131,15 +130,19 @@ namespace EVCB_OCPP.WSServer
             Task serverSetFeeTask = new Task(ServerSetFeeTrigger, _ct);
             serverSetFeeTask.Start();
 
-            Task serverWeatherNotificationTask = new Task(ServerWeatherNotificationTrigger, _ct);
-            serverWeatherNotificationTask.Start();
-
             Task serverBeatTask = new Task(HeartBeatCheckTrigger, _ct);
             serverBeatTask.Start();
 
             Task serverHealthTask = new Task(HealthCheckTrigger, _ct);
             serverHealthTask.Start();
 
+            Task smartChargingTask = new Task(SmartChargingTrigger, _ct);
+            smartChargingTask.Start();
+
+
+            Task denyModelCheckTask = new Task(()=>DenyModelCheckTrigger(false), _ct);
+            denyModelCheckTask.Start();
+
             while (true)
             {
                 var input = Console.ReadLine();
@@ -155,7 +158,6 @@ namespace EVCB_OCPP.WSServer
                         Console.WriteLine("Command GC");
                         GC.Collect();
                         break;
-
                     case "lc":
                         {
                             Console.WriteLine("Command List Clients");
@@ -166,7 +168,6 @@ namespace EVCB_OCPP.WSServer
 
                             }
                             var list = _copyClientDic.Select(c => c.Value).ToList();
-                            var locations = _copyClientDic.Where(x => !string.IsNullOrEmpty(x.Value.StationLocation)).Distinct().Select(x => x.Value.StationLocation).ToList();
                             int i = 1;
                             foreach (var c in list)
                             {
@@ -174,12 +175,6 @@ namespace EVCB_OCPP.WSServer
                                 i++;
                             }
 
-                            foreach (var c in TCCStationDic)
-                            {
-                                Console.WriteLine(i + ":" + c.Key + "-" + c.Value.Temperature + "/" + c.Value.WeatherID);
-                                i++;
-                            }
-
                         }
                         break;
                     case "lcn":
@@ -215,7 +210,6 @@ namespace EVCB_OCPP.WSServer
                         Console.WriteLine("Command clear");
                         Console.Clear();
                         break;
-
                     case "silent":
                         Console.WriteLine("Command silent");
                         var xe = XElement.Load("NLog.config");
@@ -224,7 +218,6 @@ namespace EVCB_OCPP.WSServer
                             .Where(c => c.Attribute("writeTo").Value.Equals("console")).Attributes("minlevel").FirstOrDefault();
                         if (minlevelattr != null)
                         {
-
                             minlevelattr.Value = "Warn";
                         }
                         xe.Save("NLog.config");
@@ -237,7 +230,6 @@ namespace EVCB_OCPP.WSServer
                             .Where(c => c.Attribute("writeTo").Value.Equals("console")).Attributes("minlevel").FirstOrDefault();
                         if (minlevelattr1 != null)
                         {
-
                             minlevelattr1.Value = "trace";
                         }
                         xe1.Save("NLog.config");
@@ -258,36 +250,6 @@ namespace EVCB_OCPP.WSServer
             }
         }
 
-        private void CheckVersion(string chargeBoxId)
-        {
-            if (string.IsNullOrEmpty(chargeBoxId)) return;
-            using (var db = new MainDBContext())
-            {
-                db.ServerMessage.Add(new ServerMessage()
-                {
-                    ChargeBoxId = chargeBoxId,
-                    CreatedBy = "Server",
-                    CreatedOn = DateTime.UtcNow,
-                    OutAction = Actions.DataTransfer.ToString(),
-                    OutRequest = JsonConvert.SerializeObject(
-                          new DataTransferRequest()
-                          {
-                              messageId = "ID_FirmwareVersion",
-                              vendorId = "Phihong Technology"
-
-                          },
-                          new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
-                    SerialNo = Guid.NewGuid().ToString(),
-                    InMessage = string.Empty
-
-                });
-
-                db.SaveChanges();
-            }
-
-        }
-
-
         private void CheckEVSEConfigure(string chargeBoxId)
         {
             if (string.IsNullOrEmpty(chargeBoxId)) return;
@@ -316,39 +278,6 @@ namespace EVCB_OCPP.WSServer
             }
         }
 
-
-        #region 台泥
-
-
-        private void ReadTCCSetting()
-        {
-            using (var db = new MainDBContext())
-            {
-                var info = db.Customer.Where(x => x.Id == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8")).Select(x => new { x.ApiUrl, x.ApiKey }).FirstOrDefault();
-                GlobalConfig.TCC_API_URL = info.ApiUrl;
-                GlobalConfig.TCC_SALTKEY = info.ApiKey;
-
-            }
-        }
-        async private Task<TCCStationInfoDto> GetStationInfo(string machineId)
-        {
-            TCCStationInfoDto stationInfo = null;
-            if (string.IsNullOrEmpty(machineId)) return stationInfo;
-            using (SqlConnection conn = new SqlConnection(webConnectionString))
-            {
-                var parameters = new DynamicParameters();
-                parameters.Add("@MachineId", machineId, DbType.String, ParameterDirection.Input);
-                string sql = " SELECT CAST([Latitude] as DECIMAL(5,2)) Lat,CAST([Longitude] as DECIMAL(5, 2))  Long ,SUBSTRING([Address],1,3) as zipcode FROM[StationMachine]  left join [dbo].[Station]" +
-               "  on[StationMachine].StationId = Station.[Id]  where StationMachine.MachineId=@MachineId; ";
-
-                var result = await conn.QueryAsync<TCCStationInfoDto>(sql, parameters);
-                stationInfo = result.FirstOrDefault();
-            }
-
-            return stationInfo;
-        }
-        #endregion
-
         private void OpenNetwork()
         {
 
@@ -367,6 +296,7 @@ namespace EVCB_OCPP.WSServer
             //設定server config
             var serverConfig = new ServerConfig
             {
+                SendingQueueSize = 10,
                 //Port = Convert.ToInt32(2012),
                 //Ip = "172.17.40.13",
                 MaxRequestLength = 204800,
@@ -721,7 +651,7 @@ namespace EVCB_OCPP.WSServer
                                     if (((BootNotificationConfirmation)replyResult.Message).status == Packet.Messages.SubTypes.RegistrationStatus.Accepted)
                                     {
 
-                                        CheckVersion(session.ChargeBoxId);
+
                                         CheckEVSEConfigure(session.ChargeBoxId);
                                         if (session.CustomerId == new Guid("298918C0-6BB5-421A-88CC-4922F918E85E") || session.CustomerId == new Guid("9E6BFDCC-09FB-4DAB-A428-43FE507600A3"))
                                         {
@@ -746,103 +676,8 @@ namespace EVCB_OCPP.WSServer
 
                                                 });
 
-
-                                                db.SaveChanges();
-                                            }
-
-                                        }
-
-
-                                        if (session.CustomerId == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8"))
-                                        {
-
-                                            var stationInfo = await GetStationInfo(session.MachineId);
-                                            if (stationInfo != null)
-                                            {
-                                                session.StationLocation = string.Format("{0},{1}", stationInfo.Lat, stationInfo.Long);
-                                                session.StationName = stationInfo.ZipCode;
-                                            }
-                                            using (var db = new MainDBContext())
-                                            {
-                                                db.ServerMessage.Add(new ServerMessage()
-                                                {
-                                                    ChargeBoxId = session.ChargeBoxId,
-                                                    CreatedBy = "Server",
-                                                    CreatedOn = DateTime.UtcNow,
-                                                    OutAction = Actions.DataTransfer.ToString(),
-                                                    OutRequest = JsonConvert.SerializeObject(
-                                                          new DataTransferRequest()
-                                                          {
-                                                              messageId = "ID_Station_Location",
-                                                              vendorId = "Phihong Technology",
-                                                              data = JsonConvert.SerializeObject(new { stationName = session.StationName })
-
-                                                          },
-                                                          new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
-                                                    SerialNo = Guid.NewGuid().ToString(),
-                                                    InMessage = string.Empty
-
-                                                });
-
-
-                                                db.ServerMessage.Add(new ServerMessage()
-                                                {
-                                                    ChargeBoxId = session.ChargeBoxId,
-                                                    CreatedBy = "Server",
-                                                    CreatedOn = DateTime.UtcNow,
-                                                    OutAction = Actions.ChangeConfiguration.ToString(),
-                                                    OutRequest = JsonConvert.SerializeObject(
-                                                         new ChangeConfigurationRequest()
-                                                         {
-                                                             key = "TimeOffset",
-                                                             value = "+08:00"
-
-                                                         },
-                                                         new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
-                                                    SerialNo = Guid.NewGuid().ToString(),
-                                                    InMessage = string.Empty
-
-                                                });
-
-
-                                                if (!TCCStationDic.ContainsKey(session.StationLocation))
-                                                {
-
-                                                    _CheckWeatherDt = DateTime.UtcNow.AddDays(-1);
-                                                }
-                                                else
-                                                {
-
-                                                    db.ServerMessage.Add(new ServerMessage()
-                                                    {
-                                                        ChargeBoxId = session.ChargeBoxId,
-                                                        CreatedBy = "Server",
-                                                        CreatedOn = DateTime.UtcNow,
-                                                        OutAction = Actions.DataTransfer.ToString(),
-                                                        OutRequest = JsonConvert.SerializeObject(
-                                                        new DataTransferRequest()
-                                                        {
-                                                            messageId = "ID_Weather_Info",
-                                                            vendorId = "Phihong Technology",
-                                                            data = JsonConvert.SerializeObject(
-                                                                new
-                                                                {
-                                                                    weatherId = TCCStationDic[session.StationLocation].WeatherID,
-                                                                    Temperature = TCCStationDic[session.StationLocation].Temperature
-                                                                })
-                                                        },
-                                                        new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
-                                                        SerialNo = Guid.NewGuid().ToString(),
-                                                        InMessage = string.Empty
-
-                                                    });
-
-                                                }
-
                                                 db.SaveChanges();
-
                                             }
-
                                         }
                                     }
                                     else
@@ -860,43 +695,10 @@ namespace EVCB_OCPP.WSServer
                                                 db.SaveChanges();
                                             }
                                         }
-
                                         await SetDefaultFee(session);
                                     }
                                 }
 
-                                #region 台泥
-                                if (action == Actions.StartTransaction && session.CustomerId == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8") && replyResult.Message is StartTransactionConfirmation)
-                                {
-
-                                    StartTransactionConfirmation confirm = (StartTransactionConfirmation)replyResult.Message;
-                                    StartTransactionRequest request = (StartTransactionRequest)analysisResult.Message;
-                                    using (var db = new MainDBContext())
-                                    {
-                                        db.ServerMessage.Add(new ServerMessage()
-                                        {
-                                            ChargeBoxId = session.ChargeBoxId,
-                                            CreatedBy = "Server",
-                                            CreatedOn = DateTime.UtcNow,
-                                            OutAction = Actions.DataTransfer.ToString(),
-                                            OutRequest = JsonConvert.SerializeObject(
-                                                    new DataTransferRequest()
-                                                    {
-                                                        messageId = "ID_GetTxUserInfo",
-                                                        vendorId = "Phihong Technology",
-                                                        data = JsonConvert.SerializeObject(new { txId = confirm.transactionId, ConnectorId = request.connectorId })
-                                                    },
-                                                    new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
-                                            SerialNo = Guid.NewGuid().ToString(),
-                                            InMessage = string.Empty
-
-                                        });
-
-                                        db.SaveChanges();
-                                    }
-                                }
-                                #endregion
-
                                 if (action == Actions.Authorize && replyResult.Message is AuthorizeConfirmation)
                                 {
                                     var authorizeRequest = (IRequest)analysisResult.Message as AuthorizeRequest;
@@ -953,23 +755,16 @@ namespace EVCB_OCPP.WSServer
                             if (action == Actions.StartTransaction)
                             {
                                 var stationId = _loadingBalanceService.GetStationIdByMachineId(session.MachineId);
-                                var _powerDic = _loadingBalanceService.GetSettingPower(stationId, session.MachineId);
+                                var _powerDic = await _loadingBalanceService.GetSettingPower(stationId);
                                 if (_powerDic != null)
                                 {
                                     foreach (var kv in _powerDic)
                                     {
                                         try
                                         {
-                                            string chargeBoxId = string.Empty;
-                                            //set profile
-                                            lock (_lockClientDic)
+                                            if (kv.Value.HasValue)
                                             {
-                                                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);
+                                                profileHandler.SetChargingProfile(kv.Key, kv.Value.Value, Packet.Messages.SubTypes.ChargingRateUnitType.W);
                                             }
                                         }
                                         catch (Exception ex)
@@ -984,42 +779,25 @@ namespace EVCB_OCPP.WSServer
                             if (action == Actions.StopTransaction)
                             {
                                 var stationId = _loadingBalanceService.GetStationIdByMachineId(session.MachineId);
-                                if (_loadingBalanceService.IsNeedtoCancelSetting(stationId, session.MachineId, session.ChargeBoxId))
+                                var _powerDic = await _loadingBalanceService.GetSettingPower(stationId);
+                                if (_powerDic != null)
                                 {
-                                    //Clear  current profile    
-                                    profileHandler.ClearChargingProfile(session.ChargeBoxId);
-
-                                    var _powerDic = _loadingBalanceService.GetRerangeSettingPower(stationId);
-                                    if (_powerDic != null)
+                                    foreach (var kv in _powerDic)
                                     {
-                                        foreach (var kv in _powerDic)
+                                        try
                                         {
-                                            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)
+                                            if (kv.Value.HasValue)
                                             {
-                                                logger.Error(string.Format("Set Profile Exception: {0}", ex.ToString()));
+                                                profileHandler.SetChargingProfile(kv.Key, kv.Value.Value, Packet.Messages.SubTypes.ChargingRateUnitType.W);
                                             }
-
+                                        }
+                                        catch (Exception ex)
+                                        {
+                                            logger.Error(string.Format("Set Profile Exception: {0}", ex.ToString()));
                                         }
                                     }
-
                                 }
-
                             }
-
                         }
                         break;
                     case "FirmwareManagement":
@@ -1198,7 +976,6 @@ namespace EVCB_OCPP.WSServer
             }
         }
 
-
         private void Send(ClientData session, string msg, string messageType, string errorMsg = "")
         {
             try
@@ -1219,6 +996,69 @@ namespace EVCB_OCPP.WSServer
 
         }
 
+        async private void DenyModelCheckTrigger(bool warmup)
+        {           
+            for (; ; )
+            {
+                if (_ct.IsCancellationRequested)
+                {
+                    break;
+                }
+
+                try
+                {
+                    var min_Interval = (DateTime.UtcNow - _CheckDenyListDt).TotalMinutes;
+
+                    if (min_Interval > 5)
+                    {
+                        using (SqlConnection conn = new SqlConnection(webConnectionString))
+                        {
+                            string strSql = "SELECT [Value] FROM[StandardOCPP_Web].[dbo].[KernelConfig]" +
+                             "where SystemKey = 'DenyModelNames'; ";
+                            var result = await conn.QueryAsync<string>(strSql);
+                           
+                            GlobalConfig.DenyModelNames = result.FirstOrDefault().Split(',').ToList();
+                            logger.Debug(string.Format("Current DenyList:[{0}]", string.Join(",", GlobalConfig.DenyModelNames)));
+                        }
+                        _CheckDenyListDt = DateTime.UtcNow;
+
+                        if (!string.IsNullOrEmpty(GlobalConfig.DenyModelNames[0]))
+                        {
+                            Dictionary<string, ClientData> _copyClientDic = null;
+                            lock (_lockClientDic)
+                            {
+                                _copyClientDic = new Dictionary<string, ClientData>(clientDic);
+                            }
+                            foreach (var denyName in GlobalConfig.DenyModelNames)
+                            {
+                                var removeClients = _copyClientDic.Where(x => x.Key.StartsWith(denyName)).Select(x => x.Value).ToList();
+                                foreach (var session in removeClients)
+                                {
+
+                                    Console.WriteLine(string.Format("Server forced to shut down ChargeBox ({0}: Reason: DenyModelName-{1}", session.ChargeBoxId, denyName));
+                                    RemoveClient(session);
+                                }
+                            }
+                            
+
+                           
+                        }
+
+                    }
+                   
+
+                    await Task.Delay(500);
+
+                }
+                catch (Exception ex)
+                {
+                    logger.Error(string.Format("DenyModelCheckTrigger  Ex:{0}", ex.ToString()));
+                }
+
+                if (warmup) break;
+            }
+        }
+
         async private void ServerUpdateTrigger()
         {
             for (; ; )
@@ -1241,9 +1081,6 @@ namespace EVCB_OCPP.WSServer
                     checkUpdateDt = DateTime.UtcNow;
                     using (var db = new MainDBContext())
                     {
-                        //var needUpdateChargers = db.Machine.Where(x => x.FW_AssignedMachineVersionId.HasValue == true &&
-                        //    x.FW_AssignedMachineVersionId != x.FW_VersionReport && x.Online == true)
-                        //    .Select(x => new { x.Id, x.ChargeBoxId, x.FW_AssignedMachineVersionId }).ToList();
 
                         var needUpdateChargers = db.Machine.Where(x => x.FW_AssignedVersion.HasValue == true &&
                           x.FW_AssignedVersion != x.FW_VersionReport && x.Online == true)
@@ -1253,14 +1090,10 @@ namespace EVCB_OCPP.WSServer
                         {
                             try
                             {
-
-
                                 ClientData session;
                                 if (_copyClientDic.TryGetValue(chargeBoxId, out session))
                                 {
-
                                     string requestId = Guid.NewGuid().ToString();
-                                    // using (var db = new MainDBContext())
 
                                     if (session.IsCheckIn && !session.ISOCPP20)
                                     {
@@ -1329,12 +1162,7 @@ namespace EVCB_OCPP.WSServer
                                         //}
                                         #endregion
                                     }
-
-
-
                                 }
-
-
                             }
                             catch (Exception ex)
                             {
@@ -1343,11 +1171,10 @@ namespace EVCB_OCPP.WSServer
                         }
                     }
                     await Task.Delay(1000);
-                    //  Thread.CurrentThread.Join(1000);
+
                 }
             }
         }
-        string webConnectionString = ConfigurationManager.ConnectionStrings["WebDBContext"].ConnectionString;
 
         async private void ServerMessageTrigger()
         {
@@ -1489,7 +1316,6 @@ namespace EVCB_OCPP.WSServer
             }
         }
 
-
         async private void HeartBeatCheckTrigger()
         {
             for (; ; )
@@ -1553,205 +1379,6 @@ namespace EVCB_OCPP.WSServer
             }
         }
 
-        async private void ServerWeatherNotificationTrigger()
-        {
-            for (; ; )
-            {
-                if (_ct.IsCancellationRequested)
-                {
-                    break;
-                }
-
-                var min_Interval = (DateTime.UtcNow - _CheckWeatherDt).TotalMinutes;
-
-                if (min_Interval > 30)
-                {
-                    // Console.WriteLine("in...............ServerWeatherNotificationTrigger");
-                    BasicMessageHandler msgAnalyser = new BasicMessageHandler();
-                    Dictionary<string, ClientData> _copyClientDic = null;
-                    lock (_lockClientDic)
-                    {
-                        _copyClientDic = new Dictionary<string, ClientData>(clientDic);
-
-                    }
-                    _CheckWeatherDt = DateTime.UtcNow;
-
-                    var locations = _copyClientDic.Where(x => !string.IsNullOrEmpty(x.Value.StationLocation)).Distinct().Select(x => x.Value.StationLocation).ToList();
-
-                    // Console.WriteLine("in...............ServerWeatherNotificationTrigger");
-                    foreach (var location in locations)
-                    {
-
-                        try
-                        {   //query weather
-                            var httpResult = await httpClient.GetWeather("https://api.weatherapi.com/v1/current.json?key=874346abc0874e69a9423510222201&q=" + location, null, null);
-
-                            string temp = "17";
-                            string weather_code = "1183";
-                            if (httpResult.Status == System.Net.HttpStatusCode.OK)
-                            {
-                                try
-                                {
-                                    var jsonResult = JsonConvert.DeserializeObject(httpResult.Response) as JObject;
-                                    temp = jsonResult["current"]["temp_c"].ToString();
-                                    weather_code = jsonResult["current"]["condition"]["code"].ToString();
-
-
-                                }
-                                catch (Exception ex)
-                                {
-                                    ;
-                                }
-
-                            }
-
-                            #region 台泥氣象Mapping
-                            switch (weather_code)
-                            {
-                                case "1000":
-                                    weather_code = "1";
-                                    break;
-                                case "1003":
-                                case "1006":
-                                case "1009":
-                                    weather_code = "2";
-                                    break;
-                                case "1063":
-                                case "1072":
-                                case "1150":
-                                case "1153":
-                                case "1168":
-                                case "1171":
-                                case "1180":
-                                case "1183":
-                                case "1186":
-                                case "1189":
-                                case "1192":
-                                case "1195":
-                                case "1198":
-                                case "1201":
-                                case "1237":
-                                case "1240":
-                                case "1243":
-                                case "1246":
-                                case "1261":
-                                case "1264":
-                                    weather_code = "3";
-                                    break;
-                                case "1087":
-                                case "1273":
-                                case "1276":
-                                case "1279":
-                                case "1282":
-                                    weather_code = "4";
-                                    break;
-                                case "1066":
-                                case "1069":
-                                case "1114":
-                                case "1117":
-                                case "1204":
-                                case "1207":
-                                case "1210":
-                                case "1213":
-                                case "1216":
-                                case "1219":
-                                case "1222":
-                                case "1225":
-                                case "1249":
-                                case "1252":
-                                case "1255":
-                                case "1258":
-                                    weather_code = "5";
-                                    break;
-                                case "1030":
-                                case "1135":
-                                case "1147":
-                                    weather_code = "2";
-                                    break;
-                                default:
-                                    weather_code = "2";
-                                    break;
-                            }
-                            #endregion
-
-
-                            if (TCCStationDic.ContainsKey(location))
-                            {
-                                TCCStationDic[location].Temperature = (int)double.Parse(temp);
-                                TCCStationDic[location].WeatherID = int.Parse(weather_code);
-                            }
-                            else
-                            {
-                                TCCStationDic.Add(location, new TCCWeatherDto() { WeatherID = int.Parse(weather_code), Temperature = (int)double.Parse(temp) });
-                            }
-
-                        }
-                        catch (Exception ex)
-                        {
-                            logger.Error(string.Format("ServerWeatherNotificationTrigger ChargeBoxId:{0}  Ex:{1}", location, ex.ToString()));
-                        }
-                    }
-
-                    var clients = _copyClientDic.Where(x => x.Value.CustomerId == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8")).
-                    Select(x => new { ChargeBoxId = x.Value.ChargeBoxId, StationLocation = x.Value.StationLocation }).ToList();
-
-                    using (var db = new MainDBContext())
-                    {
-
-                        foreach (var client in clients)
-                        {
-                            try
-                            {
-                                if (string.IsNullOrEmpty(client.StationLocation))
-                                {
-                                    Console.WriteLine(client.StationLocation + " is empty");
-                                    continue;
-                                }
-
-
-                                if (TCCStationDic.ContainsKey(client.StationLocation))
-                                {
-                                    db.ServerMessage.Add(new ServerMessage()
-                                    {
-                                        ChargeBoxId = client.ChargeBoxId,
-                                        CreatedBy = "Server",
-                                        CreatedOn = DateTime.UtcNow,
-                                        OutAction = Actions.DataTransfer.ToString(),
-                                        OutRequest = JsonConvert.SerializeObject(
-                                                           new DataTransferRequest()
-                                                           {
-                                                               messageId = "ID_Weather_Info",
-                                                               vendorId = "Phihong Technology",
-                                                               data = JsonConvert.SerializeObject(
-                                                                   new
-                                                                   {
-                                                                       weatherId = TCCStationDic[client.StationLocation].WeatherID,
-                                                                       Temperature = TCCStationDic[client.StationLocation].Temperature
-                                                                   })
-                                                           },
-                                                           new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
-                                        SerialNo = Guid.NewGuid().ToString(),
-                                        InMessage = string.Empty
-
-                                    });
-
-                                    await db.SaveChangesAsync();
-                                }
-                            }
-                            catch (Exception ex)
-                            {
-                                logger.Error(string.Format("ServerWeatherNotificationTrigger ChargeBoxId:{0}  Ex:{1}", client.ChargeBoxId, ex.ToString()));
-                            }
-
-
-                        }
-                    }
-
-                }
-                await Task.Delay(1000);
-            }
-        }
-
         async private void ServerSetFeeTrigger()
         {
             for (; ; )
@@ -1860,6 +1487,63 @@ namespace EVCB_OCPP.WSServer
             }
         }
 
+        async private void SmartChargingTrigger()
+        {
+            for (; ; )
+            {
+                if (_ct.IsCancellationRequested)
+                {
+                    break;
+                }
+
+                var min_Interval = (DateTime.UtcNow - _CheckLBDt).TotalMinutes;
+                if (min_Interval > 1)
+                {
+                    List<StationInfoDto> stations = null;
+                    using (SqlConnection conn = new SqlConnection(webConnectionString))
+                    {
+                        string strSql = "SELECT[Id],[LBMode],[LBCurrent] as Availability FROM[StandardOCPP_Web].[dbo].[Station]" +
+                         "where LBMode = 1; ";
+                        var result = await conn.QueryAsync<StationInfoDto>(strSql);
+                        stations = result.ToList();
+                    }
+                    foreach (var station in stations)
+                    {
+                        var compareStation = _StationInfo.Where(x => x.Id == station.Id).FirstOrDefault();
+
+                        if (compareStation == null || (station.Id == compareStation.Id && station.Availability != compareStation.Availability))
+                        {
+                            var _powerDic = await _loadingBalanceService.GetSettingPower(station.Id);
+                            if (_powerDic != null)
+                            {
+                                foreach (var kv in _powerDic)
+                                {
+                                    try
+                                    {
+
+                                        if (kv.Value.HasValue)
+                                        {
+                                            profileHandler.SetChargingProfile(kv.Key, kv.Value.Value, Packet.Messages.SubTypes.ChargingRateUnitType.W);
+                                        }
+                                    }
+                                    catch (Exception ex)
+                                    {
+                                        logger.Error(string.Format("Set Profile Exception: {0}", ex.ToString()));
+                                    }
+
+                                }
+                            }
+                        }
+
+                    }
+                    _StationInfo = stations;
+                    _CheckLBDt = DateTime.UtcNow;
+
+                }
+                await Task.Delay(1000);
+            }
+        }
+
         async private Task<string> SetDefaultFee(ClientData client)
         {
             string displayPriceText = string.Empty;
@@ -1957,7 +1641,6 @@ namespace EVCB_OCPP.WSServer
             }
         }
 
-
         private List<NeedConfirmMessage> GetResendMessage()
         {
             List<NeedConfirmMessage> sendMessages = new List<NeedConfirmMessage>();
@@ -2051,9 +1734,6 @@ namespace EVCB_OCPP.WSServer
             return confirmed;
         }
 
-
-
-
         private void RemoveClient(ClientData session)
         {
 

+ 2171 - 0
EVCB_OCPP.WSServer/ProtalServer.cs.bak

@@ -0,0 +1,2171 @@
+using Dapper;
+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.Basic;
+using EVCB_OCPP.Packet.Messages.Core;
+using EVCB_OCPP.Packet.Messages.RemoteTrigger;
+using EVCB_OCPP.WSServer.Dto;
+using EVCB_OCPP.WSServer.Helper;
+using EVCB_OCPP.WSServer.Message;
+using EVCB_OCPP.WSServer.Service;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using NLog;
+using OCPPServer.Protocol;
+using OCPPServer.SubProtocol;
+using SuperSocket.SocketBase;
+using SuperSocket.SocketBase.Config;
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Data.Entity;
+using System.Data.SqlClient;
+using System.Diagnostics;
+using System.Linq;
+using System.Security.Authentication;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Xml.Linq;
+
+
+namespace EVCB_OCPP.WSServer
+{
+    public class DestroyRequest : IRequest
+    {
+        public string Action { get; set; }
+
+        public bool TransactionRelated()
+        {
+            return false;
+        }
+
+        public bool Validate()
+        {
+            return true;
+        }
+    }
+    internal class ProtalServer
+    {
+        static private ILogger logger = NLog.LogManager.GetCurrentClassLogger();
+        private OuterHttpClient httpClient = new OuterHttpClient();
+        private DateTime lastcheckdt = DateTime.UtcNow.AddSeconds(-20);
+        private Dictionary<string, ClientData> clientDic = new Dictionary<string, ClientData>();
+        private readonly Object _lockClientDic = new object();
+        private readonly Object _lockConfirmPacketList = new object();
+        private ProfileHandler profileHandler = new ProfileHandler();
+        private List<NeedConfirmMessage> needConfirmPacketList = new List<NeedConfirmMessage>();
+        private DateTime checkUpdateDt = DateTime.UtcNow;
+        private DateTime _CheckFeeDt = DateTime.UtcNow;
+        private DateTime _CheckWeatherDt = DateTime.UtcNow;
+        private LoadingBalanceService _loadingBalanceService = new LoadingBalanceService();
+        private Dictionary<string, TCCWeatherDto> TCCStationDic = new Dictionary<string, TCCWeatherDto>();
+
+        private List<string> needConfirmActions = new List<string>()
+        {
+             "GetConfiguration",
+             "ChangeConfiguration",
+             "RemoteStartTransaction",
+             "RemoteStopTransaction",
+             "ChangeAvailability",
+             "ClearCache",
+             "DataTransfer",
+             "Reset",
+             "UnlockConnector",
+             "TriggerMessage",
+             "GetDiagnostics",
+             "UpdateFirmware",
+             "GetLocalListVersion",
+             "SendLocalList",
+             "SetChargingProfile",
+             "ClearChargingProfile",
+             "GetCompositeSchedule",
+             "ReserveNow",
+             "CancelReservation",
+             "ExtendedTriggerMessage"
+        };
+        private List<Profile> profiles = new List<Profile>()
+        {
+             new CoreProfile(),
+             new FirmwareManagementProfile(),
+             new ReservationProfile(),
+             new RemoteTriggerProfile(),
+             new SmartChargingProfile(),
+             new LocalAuthListManagementProfile(),
+             new SecurityProfile(),
+        };
+        private CancellationTokenSource _cts = new CancellationTokenSource();
+        private CancellationToken _ct;
+        private string _ocpp20NetworkSetting = "";
+
+        internal ProtalServer()
+        {
+            _ct = _cts.Token;
+            WarmUpLog();
+
+
+
+
+        }
+
+
+        internal void Start()
+        {
+
+            if (!GlobalConfig.LoadAPPConfig())
+            {
+                Console.WriteLine("Please check App.Config setting .");
+                return;
+            }
+            //ReadTCCSetting();
+            OpenNetwork();
+
+            Task serverCommandTask = new Task(ServerMessageTrigger, _ct);
+            serverCommandTask.Start();
+
+            Task serverUpdateTask = new Task(ServerUpdateTrigger, _ct);
+            serverUpdateTask.Start();
+
+            Task serverSetFeeTask = new Task(ServerSetFeeTrigger, _ct);
+            serverSetFeeTask.Start();
+
+            Task serverWeatherNotificationTask = new Task(ServerWeatherNotificationTrigger, _ct);
+            serverWeatherNotificationTask.Start();
+
+            Task serverBeatTask = new Task(HeartBeatCheckTrigger, _ct);
+            serverBeatTask.Start();
+
+            Task serverHealthTask = new Task(HealthCheckTrigger, _ct);
+            serverHealthTask.Start();
+
+            while (true)
+            {
+                var input = Console.ReadLine();
+
+                switch (input.ToLower())
+                {
+                    case "stop":
+                        Console.WriteLine("Command stop");
+                        Stop();
+                        break;
+
+                    case "gc":
+                        Console.WriteLine("Command GC");
+                        GC.Collect();
+                        break;
+
+                    case "lc":
+                        {
+                            Console.WriteLine("Command List Clients");
+                            Dictionary<string, ClientData> _copyClientDic = null;
+                            lock (_lockClientDic)
+                            {
+                                _copyClientDic = new Dictionary<string, ClientData>(clientDic);
+
+                            }
+                            var list = _copyClientDic.Select(c => c.Value).ToList();
+                            var locations = _copyClientDic.Where(x => !string.IsNullOrEmpty(x.Value.StationLocation)).Distinct().Select(x => x.Value.StationLocation).ToList();
+                            int i = 1;
+                            foreach (var c in list)
+                            {
+                                Console.WriteLine(i + ":" + c.ChargeBoxId + " " + c.SessionID);
+                                i++;
+                            }
+
+                            foreach (var c in TCCStationDic)
+                            {
+                                Console.WriteLine(i + ":" + c.Key + "-" + c.Value.Temperature + "/" + c.Value.WeatherID);
+                                i++;
+                            }
+
+                        }
+                        break;
+                    case "lcn":
+                        {
+                            Console.WriteLine("Command List Customer Name");
+                            Dictionary<string, ClientData> _copyClientDic = null;
+                            lock (_lockClientDic)
+                            {
+                                _copyClientDic = new Dictionary<string, ClientData>(clientDic);
+
+                            }
+                            var lcn = clientDic.Select(c => c.Value.CustomerName).Distinct().ToList();
+                            int iLcn = 1;
+                            foreach (var c in lcn)
+                            {
+                                Console.WriteLine(iLcn + ":" + c + ":" + clientDic.Where(z => z.Value.CustomerName == c).Count().ToString());
+                                iLcn++;
+                            }
+
+                        }
+                        break;
+                    case "help":
+                        Console.WriteLine("Command help!!");
+                        Console.WriteLine("lcn : List Customer Name");
+                        Console.WriteLine("gc : GC Collect");
+                        Console.WriteLine("lc : List Clients");
+                        Console.WriteLine("cls : clear console");
+                        Console.WriteLine("silent : silent");
+                        Console.WriteLine("show : show log");
+                        // logger.Info("rcl : show Real Connection Limit");
+                        break;
+                    case "cls":
+                        Console.WriteLine("Command clear");
+                        Console.Clear();
+                        break;
+
+                    case "silent":
+                        Console.WriteLine("Command silent");
+                        var xe = XElement.Load("NLog.config");
+                        var xns = xe.GetDefaultNamespace();
+                        var minlevelattr = xe.Descendants(xns + "rules").Elements(xns + "logger")
+                            .Where(c => c.Attribute("writeTo").Value.Equals("console")).Attributes("minlevel").FirstOrDefault();
+                        if (minlevelattr != null)
+                        {
+
+                            minlevelattr.Value = "Warn";
+                        }
+                        xe.Save("NLog.config");
+                        break;
+                    case "show":
+                        Console.WriteLine("Command show");
+                        var xe1 = XElement.Load("NLog.config");
+                        var xns1 = xe1.GetDefaultNamespace();
+                        var minlevelattr1 = xe1.Descendants(xns1 + "rules").Elements(xns1 + "logger")
+                            .Where(c => c.Attribute("writeTo").Value.Equals("console")).Attributes("minlevel").FirstOrDefault();
+                        if (minlevelattr1 != null)
+                        {
+
+                            minlevelattr1.Value = "trace";
+                        }
+                        xe1.Save("NLog.config");
+                        break;
+                    case "rcl":
+                        break;
+                    default:
+                        break;
+                }
+            }
+        }
+
+        internal void Stop()
+        {
+            if (_cts != null)
+            {
+                _cts.Cancel();
+            }
+        }
+
+        private void CheckVersion(string chargeBoxId)
+        {
+            if (string.IsNullOrEmpty(chargeBoxId)) return;
+            using (var db = new MainDBContext())
+            {
+                db.ServerMessage.Add(new ServerMessage()
+                {
+                    ChargeBoxId = chargeBoxId,
+                    CreatedBy = "Server",
+                    CreatedOn = DateTime.UtcNow,
+                    OutAction = Actions.DataTransfer.ToString(),
+                    OutRequest = JsonConvert.SerializeObject(
+                          new DataTransferRequest()
+                          {
+                              messageId = "ID_FirmwareVersion",
+                              vendorId = "Phihong Technology"
+
+                          },
+                          new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                    SerialNo = Guid.NewGuid().ToString(),
+                    InMessage = string.Empty
+
+                });
+
+                db.SaveChanges();
+            }
+
+        }
+
+
+        private void CheckEVSEConfigure(string chargeBoxId)
+        {
+            if (string.IsNullOrEmpty(chargeBoxId)) return;
+            using (var db = new MainDBContext())
+            {
+                db.ServerMessage.Add(new ServerMessage()
+                {
+                    ChargeBoxId = chargeBoxId,
+                    CreatedBy = "Server",
+                    CreatedOn = DateTime.UtcNow,
+                    OutAction = Actions.GetConfiguration.ToString(),
+                    OutRequest = JsonConvert.SerializeObject(
+                            new GetConfigurationRequest()
+                            {
+                                key = new List<string>()
+
+                            },
+                            new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                    SerialNo = Guid.NewGuid().ToString(),
+                    InMessage = string.Empty
+
+                }); ;
+
+                db.SaveChanges();
+
+            }
+        }
+
+
+        #region 台泥
+
+
+        private void ReadTCCSetting()
+        {
+            using (var db = new MainDBContext())
+            {
+                var info = db.Customer.Where(x => x.Id == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8")).Select(x => new { x.ApiUrl, x.ApiKey }).FirstOrDefault();
+                GlobalConfig.TCC_API_URL = info.ApiUrl;
+                GlobalConfig.TCC_SALTKEY = info.ApiKey;
+
+            }
+        }
+        async private Task<TCCStationInfoDto> GetStationInfo(string machineId)
+        {
+            TCCStationInfoDto stationInfo = null;
+            if (string.IsNullOrEmpty(machineId)) return stationInfo;
+            using (SqlConnection conn = new SqlConnection(webConnectionString))
+            {
+                var parameters = new DynamicParameters();
+                parameters.Add("@MachineId", machineId, DbType.String, ParameterDirection.Input);
+                string sql = " SELECT CAST([Latitude] as DECIMAL(5,2)) Lat,CAST([Longitude] as DECIMAL(5, 2))  Long ,SUBSTRING([Address],1,3) as zipcode FROM[StationMachine]  left join [dbo].[Station]" +
+               "  on[StationMachine].StationId = Station.[Id]  where StationMachine.MachineId=@MachineId; ";
+
+                var result = await conn.QueryAsync<TCCStationInfoDto>(sql, parameters);
+                stationInfo = result.FirstOrDefault();
+            }
+
+            return stationInfo;
+        }
+        #endregion
+
+        private void OpenNetwork()
+        {
+
+            //載入OCPP Protocol
+            var appServer = new OCPPWSServer(new List<OCPPSubProtocol>() { new OCPPSubProtocol(), new OCPPSubProtocol(" ocpp1.6"), new OCPPSubProtocol("ocpp2.0") });
+
+            List<IListenerConfig> llistener = new List<IListenerConfig>();
+
+            llistener.Add(new ListenerConfig { Ip = System.Net.IPAddress.Any.ToString(), Port = Convert.ToInt32(GlobalConfig.GetWS_Port()), Backlog = 100, Security = "None" });
+            llistener.Add(new ListenerConfig { Ip = System.Net.IPAddress.Any.ToString(), Port = Convert.ToInt32(GlobalConfig.GetWSS_Port()), Backlog = 100, Security = SslProtocols.Tls12.ToString() });
+
+            var config = ConfigurationManager.GetSection("superSocket") as IConfigurationSource;
+            ICertificateConfig Certificate = config.Servers.ElementAt(0).Certificate;
+            IEnumerable<IListenerConfig> listeners = llistener;
+
+            //設定server config
+            var serverConfig = new ServerConfig
+            {
+                //Port = Convert.ToInt32(2012),
+                //Ip = "172.17.40.13",
+                MaxRequestLength = 204800,
+                //Security = serverSecurity,
+                Certificate = Certificate,
+                Listeners = listeners,
+                //  LogAllSocketException = true,
+                KeepAliveTime = 10,
+                // LogBasicSessionActivity = true
+            };
+
+            //Setup with listening port
+            if (!appServer.Setup(serverConfig, logFactory: new OCPPLogFactory()))
+            {
+                Console.WriteLine("Failed to setup!");
+                return;
+            }
+
+            appServer.NewSessionConnected += AppServer_NewSessionConnected;
+            appServer.SessionClosed += AppServer_SessionClosed;
+
+
+            //Try to start the appServer
+            if (!appServer.Start())
+            {
+                Console.WriteLine("Failed to start!");
+                Console.ReadKey();
+                return;
+            }
+        }
+
+        private void AppServer_SessionClosed(ClientData session, CloseReason value)
+        {
+            WriteMachineLog(session, string.Format("CloseReason: {0}", value), "Connection", "");
+            RemoveClient(session);
+        }
+
+        private void AppServer_NewSessionConnected(ClientData session)
+        {
+            logger.Debug(string.Format("{0} NewSessionConnected", session.Path));
+
+            try
+            {
+                lock (_lockClientDic)
+                {
+                    bool isNotSupported = session.SecWebSocketProtocol.Contains("ocpp1.6") ? false : session.SecWebSocketProtocol.Contains("ocpp2.0") ? false : true;
+                    if (isNotSupported)
+                    {
+                        //logger.Debug(string.Format("ChargeBoxId:{0} SecWebSocketProtocol:{1} NotSupported", session.ChargeBoxId, session.SecWebSocketProtocol));
+                        WriteMachineLog(session, string.Format("SecWebSocketProtocol:{0} NotSupported", session.SecWebSocketProtocol), "Connection", "");
+                        return;
+                    }
+                    ClientData _removeClient = null;
+
+
+                    clientDic.TryGetValue(session.ChargeBoxId, out _removeClient);
+                    if (_removeClient != null)
+                    {
+                        WriteMachineLog(_removeClient, "Duplicate Logins", "Connection", "");
+                        _removeClient.Close(CloseReason.ServerShutdown);
+                        RemoveClient(_removeClient);
+                    }
+
+                    clientDic.Add(session.ChargeBoxId, session);
+                    session.m_ReceiveData += new ClientData.OCPPClientDataEventHandler<ClientData, String>(ReceivedMessage);
+                    // logger.Debug("------------New " + (session == null ? "Oops" : session.ChargeBoxId));
+                    WriteMachineLog(session, "NewSessionConnected", "Connection", "");
+
+                    using (var db = new MainDBContext())
+                    {
+                        var machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault();
+                        if (machine != null)
+                        {
+                            machine.ConnectionType = session.Origin.Contains("https") ? 2 : 1;
+                            db.SaveChanges();
+                        }
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                logger.Error(string.Format("NewSessionConnected Ex: {0}", ex.ToString()));
+            }
+
+
+        }
+
+        async private void ReceivedMessage(ClientData session, string rawdata)
+        {
+            try
+            {
+                BasicMessageHandler msgAnalyser = new BasicMessageHandler();
+                MessageResult analysisResult = msgAnalyser.AnalysisReceiveData(session, rawdata);
+
+                WriteMachineLog(session, rawdata,
+                     string.Format("{0} {1}", string.IsNullOrEmpty(analysisResult.Action) ? "unknown" : analysisResult.Action, analysisResult.Id == 2 ? "Request" : (analysisResult.Id == 3 ? "Confirmation" : "Error")), analysisResult.Exception == null ? "" : analysisResult.Exception.Message);
+
+                if (session.ResetSecurityProfile)
+                {
+                    logger.Error(string.Format("[{0}] ChargeBoxId:{1} ResetSecurityProfile", DateTime.UtcNow, session.ChargeBoxId));
+                    RemoveClient(session);
+                    return;
+                }
+
+
+                if (!analysisResult.Success)
+                {
+                    //解析RawData就發生錯誤
+                    if (!string.IsNullOrEmpty(analysisResult.CallErrorMsg))
+                    {
+                        Send(session, analysisResult.CallErrorMsg, string.Format("{0} {1}", analysisResult.Action, "Error"));
+                    }
+                    else
+                    {
+                        if (analysisResult.Message == null)
+                        {
+                            string replyMsg = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
+                            string errorMsg = string.Empty;
+                            if (analysisResult.Exception != null)
+                            {
+                                errorMsg = analysisResult.Exception.ToString();
+                            }
+
+                            Send(session, replyMsg, string.Format("{0} {1}", "unknown", "Error"), "EVSE's sent essage has parsed Failed. ");
+                        }
+                        else
+                        {
+                            BaseMessage _baseMsg = analysisResult.Message as BaseMessage;
+
+
+                            string replyMsg = BasicMessageHandler.GenerateCallError(_baseMsg.Id, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
+                            string errorMsg = string.Empty;
+                            if (analysisResult.Exception != null)
+                            {
+                                errorMsg = analysisResult.Exception.ToString();
+                            }
+
+                            Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
+                        }
+
+                    }
+                }
+                else
+                {
+                    switch (analysisResult.Id)
+                    {
+                        case BasicMessageHandler.TYPENUMBER_CALL:
+                            {
+                                if (!session.ISOCPP20)
+                                {
+                                    Actions action = Convertor.GetAction(analysisResult.Action);
+                                    ProcessRequestMessage(analysisResult, session, action);
+                                }
+                                else
+                                {
+                                    EVCB_OCPP20.Packet.Features.Actions action = Convertor.GetActionby20(analysisResult.Action);
+                                    MessageResult result = new MessageResult() { Success = true };
+                                    //ocpp20 處理
+                                    switch (action)
+                                    {
+
+                                        case EVCB_OCPP20.Packet.Features.Actions.BootNotification:
+                                            {
+                                                EVCB_OCPP20.Packet.Messages.BootNotificationRequest _request = (EVCB_OCPP20.Packet.Messages.IRequest)analysisResult.Message as EVCB_OCPP20.Packet.Messages.BootNotificationRequest;
+
+                                                var confirm = new EVCB_OCPP20.Packet.Messages.BootNotificationResponse() { CurrentTime = DateTime.UtcNow, Interval = 180, Status = EVCB_OCPP20.Packet.DataTypes.EnumTypes.RegistrationStatusEnumType.Pending };
+
+                                                result.Message = confirm;
+                                                result.Success = true;
+
+                                                string response = BasicMessageHandler.GenerateConfirmationofOCPP20(analysisResult.UUID, (EVCB_OCPP20.Packet.Messages.IConfirmation)result.Message);
+                                                Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Response"), result.Exception == null ? string.Empty : result.Exception.ToString());
+
+
+                                                var request = new EVCB_OCPP20.Packet.Messages.SetNetworkProfileRequest()
+                                                {
+                                                    ConfigurationSlot = 1,
+                                                    ConnectionData = new EVCB_OCPP20.Packet.DataTypes.NetworkConnectionProfileType()
+                                                    {
+                                                        OcppVersion = EVCB_OCPP20.Packet.DataTypes.EnumTypes.OCPPVersionEnumType.OCPP20,
+                                                        OcppTransport = EVCB_OCPP20.Packet.DataTypes.EnumTypes.OCPPTransportEnumType.JSON,
+                                                        MessageTimeout = 30,
+                                                        OcppCsmsUrl = session.UriScheme == "ws" ? GlobalConfig.OCPP20_WSUrl : GlobalConfig.OCPP20_WSSUrl,
+                                                        OcppInterface = EVCB_OCPP20.Packet.DataTypes.EnumTypes.OCPPInterfaceEnumType.Wired0
+                                                    }
+
+                                                };
+                                                var uuid = session.queue20.store(request);
+                                                string requestText = BasicMessageHandler.GenerateRequestofOCPP20(uuid, "SetNetworkProfile", request);
+                                                Send(session, requestText, "SetNetworkProfile");
+
+                                            }
+                                            break;
+                                        default:
+                                            {
+                                                logger.Error(string.Format("We don't implement messagetype:{0} of raw data :{1} by {2}", analysisResult.Id, rawdata, session.ChargeBoxId));
+                                            }
+                                            break;
+                                    }
+
+                                }
+                            }
+                            break;
+                        case BasicMessageHandler.TYPENUMBER_CALLRESULT:
+                            {
+                                if (!session.ISOCPP20)
+                                {
+                                    Actions action = Convertor.GetAction(analysisResult.Action);
+                                    ProcessConfirmationMessage(analysisResult, session, action);
+                                }
+                                else
+                                {
+                                    EVCB_OCPP20.Packet.Features.Actions action = Convertor.GetActionby20(analysisResult.Action);
+                                    MessageResult result = new MessageResult() { Success = true };
+                                    //ocpp20 處理
+                                    switch (action)
+                                    {
+
+                                        case EVCB_OCPP20.Packet.Features.Actions.SetNetworkProfile:
+                                            {
+                                                EVCB_OCPP20.Packet.Messages.SetNetworkProfileResponse response = (EVCB_OCPP20.Packet.Messages.IConfirmation)analysisResult.Message as EVCB_OCPP20.Packet.Messages.SetNetworkProfileResponse;
+
+                                                if (response.Status == EVCB_OCPP20.Packet.DataTypes.EnumTypes.SetNetworkProfileStatusEnumType.Accepted)
+                                                {
+                                                    var request = new EVCB_OCPP20.Packet.Messages.SetVariablesRequest()
+                                                    {
+                                                        SetVariableData = new List<EVCB_OCPP20.Packet.DataTypes.SetVariableDataType>()
+                                                         {
+                                                              new EVCB_OCPP20.Packet.DataTypes.SetVariableDataType()
+                                                              {
+                                                                    Component=new EVCB_OCPP20.Packet.DataTypes.ComponentType()
+                                                                    {
+                                                                         Name="OCPPCommCtrlr",
+
+                                                                    },
+                                                                     AttributeType= EVCB_OCPP20.Packet.DataTypes.EnumTypes.AttributeEnumType.Actual,
+                                                                     AttributeValue= JsonConvert.SerializeObject(new List<int>(){ 1 }),
+                                                                     Variable=new EVCB_OCPP20.Packet.DataTypes.VariableType()
+                                                                    {
+                                                                            Name="NetworkConfigurationPriority",
+
+                                                                    }
+
+
+                                                              }
+                                                         }
+
+                                                    };
+                                                    var uuid = session.queue20.store(request);
+                                                    string requestText = BasicMessageHandler.GenerateRequestofOCPP20(uuid, "SetVariables", request);
+                                                    Send(session, requestText, "SetVariables");
+                                                }
+
+                                            }
+                                            break;
+                                        case EVCB_OCPP20.Packet.Features.Actions.SetVariables:
+                                            {
+                                                EVCB_OCPP20.Packet.Messages.SetVariablesResponse response = (EVCB_OCPP20.Packet.Messages.IConfirmation)analysisResult.Message as EVCB_OCPP20.Packet.Messages.SetVariablesResponse;
+
+                                                if (response.SetVariableResult[0].AttributeStatus == EVCB_OCPP20.Packet.DataTypes.EnumTypes.SetVariableStatusEnumType.RebootRequired)
+                                                {
+                                                    var request = new EVCB_OCPP20.Packet.Messages.ResetRequest()
+                                                    {
+                                                        Type = EVCB_OCPP20.Packet.DataTypes.EnumTypes.ResetEnumType.OnIdle
+
+                                                    };
+                                                    var uuid = session.queue20.store(request);
+                                                    string requestText = BasicMessageHandler.GenerateRequestofOCPP20(uuid, "Reset", request);
+                                                    Send(session, requestText, "Reset");
+
+                                                }
+                                            }
+                                            break;
+                                        default:
+                                            {
+                                                logger.Error(string.Format("We don't implement messagetype:{0} of raw data :{1} by {2}", analysisResult.Id, rawdata, session.ChargeBoxId));
+                                            }
+                                            break;
+                                    }
+                                }
+
+                            }
+                            break;
+                        case BasicMessageHandler.TYPENUMBER_CALLERROR:
+                            {
+                                //只處理 丟出Request 收到Error的訊息                              
+                                if (analysisResult.Success && analysisResult.Message != null)
+                                {
+                                    Actions action = Convertor.GetAction(analysisResult.Action);
+                                    ProcessErrorMessage(analysisResult, session, action);
+                                }
+
+                            }
+                            break;
+                        default:
+                            {
+                                logger.Error(string.Format("Can't analyze messagetype:{0} of raw data :{1} by {2}", analysisResult.Id, rawdata, session.ChargeBoxId));
+                            }
+                            break;
+
+                    }
+                }
+
+                await Task.Delay(10);
+            }
+            catch (Exception ex)
+            {
+
+
+                if (ex.InnerException != null)
+                {
+                    logger.Error(string.Format("{0} **Inner Exception :{1} ", session.ChargeBoxId + rawdata, ex.ToString()));
+
+
+                }
+                else
+                {
+                    logger.Error(string.Format("{0} **Exception :{1} ", session.ChargeBoxId, ex.ToString()));
+                }
+            }
+
+
+        }
+
+        async private void ProcessRequestMessage(MessageResult analysisResult, ClientData session, Actions action)
+        {
+            BasicMessageHandler msgAnalyser = new BasicMessageHandler();
+            if (!session.IsCheckIn && action != Actions.BootNotification)
+            {
+                string response = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.GenericError, OCPPErrorDescription.NotChecked);
+                Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Error"));
+            }
+            else
+            {
+                var profileName = profiles.Where(x => x.IsExisted(analysisResult.Action)).Select(x => x.Name).FirstOrDefault();
+                switch (profileName)
+                {
+                    case "Core":
+                        {
+
+                            var replyResult = await profileHandler.ExecuteCoreRequest(action, session, (IRequest)analysisResult.Message).ConfigureAwait(false);
+                            if (replyResult.Success)
+                            {
+                                string response = BasicMessageHandler.GenerateConfirmation(analysisResult.UUID, (IConfirmation)replyResult.Message);
+
+
+                                Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Confirmation"), replyResult.Exception == null ? string.Empty : replyResult.Exception.ToString());
+
+                                if (action == Actions.BootNotification && replyResult.Message is BootNotificationConfirmation)
+                                {
+                                    session.IsCheckIn = true;
+                                    if (((BootNotificationConfirmation)replyResult.Message).status == Packet.Messages.SubTypes.RegistrationStatus.Accepted)
+                                    {
+
+                                        CheckVersion(session.ChargeBoxId);
+                                        CheckEVSEConfigure(session.ChargeBoxId);
+                                        if (session.CustomerId == new Guid("298918C0-6BB5-421A-88CC-4922F918E85E") || session.CustomerId == new Guid("9E6BFDCC-09FB-4DAB-A428-43FE507600A3"))
+                                        {
+                                            using (var db = new MainDBContext())
+                                            {
+                                                db.ServerMessage.Add(new ServerMessage()
+                                                {
+                                                    ChargeBoxId = session.ChargeBoxId,
+                                                    CreatedBy = "Server",
+                                                    CreatedOn = DateTime.UtcNow,
+                                                    OutAction = Actions.ChangeConfiguration.ToString(),
+                                                    OutRequest = JsonConvert.SerializeObject(
+                                                   new ChangeConfigurationRequest()
+                                                   {
+                                                       key = "TimeOffset",
+                                                       value = "+08:00"
+
+                                                   },
+                                                   new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                                    SerialNo = Guid.NewGuid().ToString(),
+                                                    InMessage = string.Empty
+
+                                                });
+
+
+                                                db.SaveChanges();
+                                            }
+
+                                        }
+
+
+                                        if (session.CustomerId == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8"))
+                                        {
+
+                                            var stationInfo = await GetStationInfo(session.MachineId);
+                                            if (stationInfo != null)
+                                            {
+                                                session.StationLocation = string.Format("{0},{1}", stationInfo.Lat, stationInfo.Long);
+                                                session.StationName = stationInfo.ZipCode;
+                                            }
+                                            using (var db = new MainDBContext())
+                                            {
+                                                db.ServerMessage.Add(new ServerMessage()
+                                                {
+                                                    ChargeBoxId = session.ChargeBoxId,
+                                                    CreatedBy = "Server",
+                                                    CreatedOn = DateTime.UtcNow,
+                                                    OutAction = Actions.DataTransfer.ToString(),
+                                                    OutRequest = JsonConvert.SerializeObject(
+                                                          new DataTransferRequest()
+                                                          {
+                                                              messageId = "ID_Station_Location",
+                                                              vendorId = "Phihong Technology",
+                                                              data = JsonConvert.SerializeObject(new { stationName = session.StationName })
+
+                                                          },
+                                                          new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                                    SerialNo = Guid.NewGuid().ToString(),
+                                                    InMessage = string.Empty
+
+                                                });
+
+
+                                                db.ServerMessage.Add(new ServerMessage()
+                                                {
+                                                    ChargeBoxId = session.ChargeBoxId,
+                                                    CreatedBy = "Server",
+                                                    CreatedOn = DateTime.UtcNow,
+                                                    OutAction = Actions.ChangeConfiguration.ToString(),
+                                                    OutRequest = JsonConvert.SerializeObject(
+                                                         new ChangeConfigurationRequest()
+                                                         {
+                                                             key = "TimeOffset",
+                                                             value = "+08:00"
+
+                                                         },
+                                                         new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                                    SerialNo = Guid.NewGuid().ToString(),
+                                                    InMessage = string.Empty
+
+                                                });
+
+
+                                                if (!TCCStationDic.ContainsKey(session.StationLocation))
+                                                {
+
+                                                    _CheckWeatherDt = DateTime.UtcNow.AddDays(-1);
+                                                }
+                                                else
+                                                {
+
+                                                    db.ServerMessage.Add(new ServerMessage()
+                                                    {
+                                                        ChargeBoxId = session.ChargeBoxId,
+                                                        CreatedBy = "Server",
+                                                        CreatedOn = DateTime.UtcNow,
+                                                        OutAction = Actions.DataTransfer.ToString(),
+                                                        OutRequest = JsonConvert.SerializeObject(
+                                                        new DataTransferRequest()
+                                                        {
+                                                            messageId = "ID_Weather_Info",
+                                                            vendorId = "Phihong Technology",
+                                                            data = JsonConvert.SerializeObject(
+                                                                new
+                                                                {
+                                                                    weatherId = TCCStationDic[session.StationLocation].WeatherID,
+                                                                    Temperature = TCCStationDic[session.StationLocation].Temperature
+                                                                })
+                                                        },
+                                                        new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                                        SerialNo = Guid.NewGuid().ToString(),
+                                                        InMessage = string.Empty
+
+                                                    });
+
+                                                }
+
+                                                db.SaveChanges();
+
+                                            }
+
+                                        }
+                                    }
+                                    else
+                                    {
+                                        using (var db = new MainDBContext())
+                                        {
+                                            var machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault();
+                                            if (machine != null)
+                                            {
+                                                if (machine.ConnectorType.Contains("6") || machine.ConnectorType.Contains("7") || machine.ConnectorType.Contains("8") || machine.ConnectorType.Contains("9"))
+                                                {
+                                                    session.IsAC = false;
+                                                }
+                                                machine.ConnectionType = session.Origin.Contains("https") ? 2 : 1;
+                                                db.SaveChanges();
+                                            }
+                                        }
+
+                                        await SetDefaultFee(session);
+                                    }
+                                }
+
+                                #region 台泥
+                                if (action == Actions.StartTransaction && session.CustomerId == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8") && replyResult.Message is StartTransactionConfirmation)
+                                {
+
+                                    StartTransactionConfirmation confirm = (StartTransactionConfirmation)replyResult.Message;
+                                    StartTransactionRequest request = (StartTransactionRequest)analysisResult.Message;
+                                    using (var db = new MainDBContext())
+                                    {
+                                        db.ServerMessage.Add(new ServerMessage()
+                                        {
+                                            ChargeBoxId = session.ChargeBoxId,
+                                            CreatedBy = "Server",
+                                            CreatedOn = DateTime.UtcNow,
+                                            OutAction = Actions.DataTransfer.ToString(),
+                                            OutRequest = JsonConvert.SerializeObject(
+                                                    new DataTransferRequest()
+                                                    {
+                                                        messageId = "ID_GetTxUserInfo",
+                                                        vendorId = "Phihong Technology",
+                                                        data = JsonConvert.SerializeObject(new { txId = confirm.transactionId, ConnectorId = request.connectorId })
+                                                    },
+                                                    new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                            SerialNo = Guid.NewGuid().ToString(),
+                                            InMessage = string.Empty
+
+                                        });
+
+                                        db.SaveChanges();
+                                    }
+                                }
+                                #endregion
+
+                                if (action == Actions.Authorize && replyResult.Message is AuthorizeConfirmation)
+                                {
+                                    var authorizeRequest = (IRequest)analysisResult.Message as AuthorizeRequest;
+                                    if (session.UserDisplayPrices.ContainsKey(authorizeRequest.idTag))
+                                    {
+                                        using (var db = new MainDBContext())
+                                        {
+                                            db.ServerMessage.Add(new ServerMessage()
+                                            {
+                                                ChargeBoxId = session.ChargeBoxId,
+                                                CreatedBy = "Server",
+                                                CreatedOn = DateTime.UtcNow,
+                                                OutAction = Actions.DataTransfer.ToString(),
+                                                OutRequest = JsonConvert.SerializeObject(
+                                                           new DataTransferRequest()
+                                                           {
+                                                               messageId = "SetUserPrice",
+                                                               vendorId = "Phihong Technology",
+                                                               data = JsonConvert.SerializeObject(
+                                                                   new
+                                                                   {
+                                                                       idToken = authorizeRequest.idTag,
+                                                                       price = session.UserDisplayPrices[authorizeRequest.idTag]
+
+                                                                   })
+                                                           },
+                                                           new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                                SerialNo = Guid.NewGuid().ToString(),
+                                                InMessage = string.Empty
+
+                                            });
+
+                                            db.SaveChanges();
+                                        }
+                                    }
+                                }
+
+                            }
+                            else
+                            {
+                                if (action == Actions.StopTransaction && replyResult.CallErrorMsg == "Reject Response Message")
+                                {
+                                    //do nothing 
+                                }
+                                else
+                                {
+                                    string response = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
+                                    string errorMsg = replyResult.Exception != null ? replyResult.Exception.ToString() : string.Empty;
+
+                                    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":
+                        {
+                            var replyResult = profileHandler.ExecuteFirmwareManagementRequest(action, session, (IRequest)analysisResult.Message);
+                            if (replyResult.Success)
+                            {
+                                string response = BasicMessageHandler.GenerateConfirmation(analysisResult.UUID, (IConfirmation)replyResult.Message);
+                                Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Confirmation", replyResult.Exception == null ? string.Empty : replyResult.Exception.ToString()));
+
+                            }
+                            else
+                            {
+                                string response = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
+                                string errorMsg = replyResult.Exception != null ? replyResult.Exception.ToString() : string.Empty;
+
+                                Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
+                            }
+
+                        }
+                        break;
+                    case "Security":
+                        {
+                            var replyResult = profileHandler.ExecuteSecurityRequest(action, session, (IRequest)analysisResult.Message);
+                            if (replyResult.Success)
+                            {
+                                string response = BasicMessageHandler.GenerateConfirmation(analysisResult.UUID, (IConfirmation)replyResult.Message);
+                                Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Confirmation", replyResult.Exception == null ? string.Empty : replyResult.Exception.ToString()));
+
+                            }
+                            else
+                            {
+                                string response = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
+                                string errorMsg = replyResult.Exception != null ? replyResult.Exception.ToString() : string.Empty;
+
+                                Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
+                            }
+                        }
+                        break;
+                    default:
+                        {
+                            string replyMsg = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
+                            string errorMsg = string.Format("Couldn't find action name: {0} of profile", action);
+                            Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
+                        }
+                        break;
+
+                }
+            }
+        }
+
+        async private void ProcessConfirmationMessage(MessageResult analysisResult, ClientData session, Actions action)
+        {
+
+            BasicMessageHandler msgAnalyser = new BasicMessageHandler();
+            if (ReConfirmMessage(analysisResult))
+            {
+                var profileName = profiles.Where(x => x.IsExisted(analysisResult.Action)).Select(x => x.Name).FirstOrDefault();
+                MessageResult confirmResult = null;
+                switch (profileName)
+                {
+                    case "Core":
+                        {
+                            confirmResult = await profileHandler.ExecuteCoreConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
+                        }
+                        break;
+                    case "FirmwareManagement":
+                        {
+                            confirmResult = profileHandler.ExecuteFirmwareManagementConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
+                        }
+                        break;
+                    case "RemoteTrigger":
+                        {
+                            confirmResult = profileHandler.ExecuteRemoteTriggerConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
+                        }
+                        break;
+                    case "Reservation":
+                        {
+                            confirmResult = profileHandler.ExecuteReservationConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
+                        }
+                        break;
+                    case "LocalAuthListManagement":
+                        {
+                            confirmResult = profileHandler.ExecuteLocalAuthListManagementConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
+                        }
+                        break;
+                    case "SmartCharging":
+                        {
+                            confirmResult = profileHandler.ExecuteSmartChargingConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
+                        }
+                        break;
+                    case "Security":
+                        {
+                            confirmResult = profileHandler.ExecuteSecurityConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
+                        }
+                        break;
+                    default:
+                        {
+                            string replyMsg = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
+                            string errorMsg = string.Format("Couldn't find action name: {0} of profile", action);
+                            Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
+                        }
+                        break;
+
+                }
+
+                if (confirmResult == null || !confirmResult.Success)
+                {
+                    logger.Error(string.Format("Action:{0} MessageId:{1}  ExecuteConfirm Error:{2} ",
+                        analysisResult.Action, analysisResult.UUID, confirmResult.Exception.ToString()));
+                }
+            }
+            else
+            {
+                string replyMsg = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
+                string errorMsg = string.Format("Action:{0} MessageId:{1}  didn't exist in confirm message", analysisResult.Action, analysisResult.UUID);
+                Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
+            }
+        }
+
+        private void ProcessErrorMessage(MessageResult analysisResult, ClientData session, Actions action)
+        {
+            BasicMessageHandler msgAnalyser = new BasicMessageHandler();
+            if (ReConfirmMessage(analysisResult))
+            {
+                var profileName = profiles.Where(x => x.IsExisted(analysisResult.Action)).Select(x => x.Name).FirstOrDefault();
+                switch (profileName)
+                {
+                    case "Core":
+                        {
+                            profileHandler.ReceivedCoreError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId);
+                        }
+                        break;
+                    case "FirmwareManagement":
+                        {
+                            profileHandler.ReceivedFirmwareManagementError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId);
+                        }
+                        break;
+                    case "RemoteTrigger":
+                        {
+                            profileHandler.ReceivedRemoteTriggerError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId);
+                        }
+                        break;
+                    case "Reservation":
+                        {
+                            profileHandler.ExecuteReservationError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId);
+                        }
+                        break;
+                    case "LocalAuthListManagement":
+                        {
+                            profileHandler.ReceivedLocalAuthListManagementError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId);
+                        }
+                        break;
+                    case "SmartCharging":
+                        {
+                            profileHandler.ReceivedSmartChargingError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId);
+                        }
+                        break;
+                    default:
+                        {
+                            string replyMsg = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
+                            string errorMsg = string.Format("Couldn't find action name: {0} of profile", action);
+                            Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
+                        }
+                        break;
+
+                }
+            }
+            else
+            {
+                string replyMsg = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
+                string errorMsg = string.Format("Action:{0} MessageId:{1}  didn't exist in confirm message", analysisResult.Action, analysisResult.UUID);
+                Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
+
+
+            }
+        }
+
+
+        private void Send(ClientData session, string msg, string messageType, string errorMsg = "")
+        {
+            try
+            {
+
+                if (session != null)
+                {
+                    WriteMachineLog(session, msg, messageType, errorMsg, true);
+                    session.Send(msg);
+                }
+
+            }
+            catch (Exception ex)
+            {
+                logger.Error(string.Format("Send Ex:{0}", ex.ToString()));
+            }
+
+
+        }
+
+        async private void ServerUpdateTrigger()
+        {
+            for (; ; )
+            {
+                if (_ct.IsCancellationRequested)
+                {
+                    break;
+                }
+
+                var min_Interval = (DateTime.UtcNow - checkUpdateDt).TotalMinutes;
+                if (min_Interval > 3)
+                {
+                    BasicMessageHandler msgAnalyser = new BasicMessageHandler();
+                    Dictionary<string, ClientData> _copyClientDic = null;
+                    lock (_lockClientDic)
+                    {
+                        _copyClientDic = new Dictionary<string, ClientData>(clientDic);
+
+                    }
+                    checkUpdateDt = DateTime.UtcNow;
+                    using (var db = new MainDBContext())
+                    {
+                        //var needUpdateChargers = db.Machine.Where(x => x.FW_AssignedMachineVersionId.HasValue == true &&
+                        //    x.FW_AssignedMachineVersionId != x.FW_VersionReport && x.Online == true)
+                        //    .Select(x => new { x.Id, x.ChargeBoxId, x.FW_AssignedMachineVersionId }).ToList();
+
+                        var needUpdateChargers = db.Machine.Where(x => x.FW_AssignedVersion.HasValue == true &&
+                          x.FW_AssignedVersion != x.FW_VersionReport && x.Online == true)
+                          .Select(x => x.ChargeBoxId).AsNoTracking().ToList();
+
+                        foreach (var chargeBoxId in needUpdateChargers)
+                        {
+                            try
+                            {
+
+
+                                ClientData session;
+                                if (_copyClientDic.TryGetValue(chargeBoxId, out session))
+                                {
+
+                                    string requestId = Guid.NewGuid().ToString();
+                                    // using (var db = new MainDBContext())
+
+                                    if (session.IsCheckIn && !session.ISOCPP20)
+                                    {
+
+                                        var _request = new TriggerMessageRequest()
+                                        {
+                                            requestedMessage = Packet.Messages.SubTypes.MessageTrigger.FirmwareStatusNotification
+                                        };
+
+                                        var uuid = session.queue.store(_request);
+                                        string rawRequest = BasicMessageHandler.GenerateRequest(uuid, _request.Action, _request);
+                                        Send(session, rawRequest, string.Format("{0} {1}", _request.Action, "Request"), "");
+
+                                        #region OCTT   ,測試韌體更新方式
+                                        //--------------------> OCTT   ,測試韌體更新方式
+                                        //{
+                                        //    var machine = db.Machine.Where(x => x.FW_AssignedMachineVersionId.HasValue == true &&
+                                        //        x.FW_AssignedMachineVersionId != x.FW_VersionReport && x.ChargeBoxId == session.ChargeBoxId)
+                                        //        .Select(x => new { x.Id, x.FW_AssignedMachineVersionId }).FirstOrDefault();
+
+                                        //    if (machine != null)
+                                        //    {
+                                        //        var mv = db.MachineVersion.Include(c => c.PublishVersion)
+                                        //         .Include(c => c.PublishVersion.PublishVersionFiles)
+                                        //         .Include(c => c.PublishVersion.PublishVersionFiles.Select(z => z.UploadFile))
+                                        //         .Where(c => c.Id == machine.FW_AssignedMachineVersionId.Value).First();
+
+                                        //        string downloadUrl = mv.PublishVersion.PublishVersionFiles.FirstOrDefault().UploadFile.FileUrl;
+
+                                        //        var _updateFWrequest = new UpdateFirmwareRequest()
+                                        //        {
+                                        //            location = new Uri(downloadUrl),
+                                        //            retries = 3,
+                                        //            retrieveDate = DateTime.UtcNow,
+                                        //            retryInterval = 10
+                                        //        };
+                                        //        db.MachineOperateRecord.Add(new MachineOperateRecord()
+                                        //        {
+                                        //            CreatedOn = DateTime.UtcNow,
+                                        //            ChargeBoxId = session.ChargeBoxId,
+                                        //            SerialNo = requestId,
+                                        //            RequestContent = JsonConvert.SerializeObject(_updateFWrequest, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                        //            EVSE_Status = 0,
+                                        //            EVSE_Value = "Fw Version:" + machine.FW_AssignedMachineVersionId,
+                                        //            Status = 0,
+                                        //            RequestType = 0,
+
+                                        //        });
+
+                                        //        db.ServerMessage.Add(new ServerMessage()
+                                        //        {
+                                        //            ChargeBoxId = session.ChargeBoxId,
+                                        //            CreatedBy = "Server",
+                                        //            CreatedOn = DateTime.UtcNow,
+                                        //            OutAction = _updateFWrequest.Action.ToString(),
+                                        //            OutRequest = JsonConvert.SerializeObject(_updateFWrequest, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                        //            SerialNo = requestId,
+                                        //            InMessage = string.Empty
+
+                                        //        });
+
+                                        //        db.SaveChanges();
+
+                                        //    }
+
+                                        //}
+                                        #endregion
+                                    }
+
+
+
+                                }
+
+
+                            }
+                            catch (Exception ex)
+                            {
+                                logger.Error(string.Format("serverUpdateTrigger ChargeBoxId:{0}  Ex:{1}", chargeBoxId, ex.ToString()));
+                            }
+                        }
+                    }
+                    await Task.Delay(1000);
+                    //  Thread.CurrentThread.Join(1000);
+                }
+            }
+        }
+        string webConnectionString = ConfigurationManager.ConnectionStrings["WebDBContext"].ConnectionString;
+
+        async private void ServerMessageTrigger()
+        {
+            for (; ; )
+            {
+                if (_ct.IsCancellationRequested)
+                {
+                    break;
+                }
+
+                try
+                {
+                    RemoveConfirmMessage();
+
+                    BasicMessageHandler msgAnalyser = new BasicMessageHandler();
+                    using (var db = new MainDBContext())
+                    {
+                        DateTime startDt = DateTime.UtcNow.AddSeconds(-30);
+                        DateTime dt = new DateTime(1991, 1, 1);
+                        DateTime currentTime = DateTime.UtcNow;
+                        var commandList = db.ServerMessage.Where(c => c.ReceivedOn == dt && c.UpdatedOn == dt && c.CreatedOn >= startDt && c.CreatedOn <= currentTime).AsNoTracking().ToList();
+
+
+                        //處理主機傳送的有指令
+                        var cmdMachineList = commandList.Select(c => c.ChargeBoxId).Distinct().ToList();
+                        if (commandList.Count > 0)
+                        {
+                            // Console.WriteLine(string.Format("Now:{0} commandList Count:{1} ", DateTime.UtcNow.ToString("yyyy/MM/dd HH:mm:ss"), commandList.Count));
+                        }
+                        var resendList = GetResendMessage();
+                        foreach (var resendItem in resendList)
+                        {
+                            ClientData session;
+                            if (clientDic.TryGetValue(resendItem.ChargePointSerialNumber, out session))
+                            {
+                                if (DateTime.UtcNow.Subtract(resendItem.SentOn).TotalSeconds > 1)
+                                {
+                                    resendItem.SentTimes--;
+                                    resendItem.SentOn = DateTime.UtcNow;
+                                    Send(session, resendItem.SentMessage, string.Format("{0} {1}", resendItem.SentAction, "Request"), "");
+                                }
+
+                            }
+
+                        }
+                        foreach (var charger_SN in cmdMachineList)
+                        {
+                            ClientData session;
+                            string uuid = string.Empty;
+                            if (clientDic.TryGetValue(charger_SN, out session))
+                            {
+                                //logger.Debug(string.Format("charger_SN:{0} startDt:{1} CreatedOn:{2}", charger_SN, startDt.ToString("yyyy/MM/dd HH:mm:ss"), DateTime.UtcNow.ToString("yyyy/MM/dd HH:mm:ss")));
+
+                                if (session.IsCheckIn && !session.ISOCPP20)
+                                {
+                                    string rawRequest = string.Empty;
+
+                                    var cmdList = commandList.Where(c => c.ChargeBoxId == charger_SN).ToList();
+
+                                    foreach (var item in cmdList)
+                                    {
+                                        IRequest request = null;
+                                        Actions action = Actions.None;
+                                        Enum.TryParse(item.OutAction, out action);
+                                        Type _RequestType = null;
+
+                                        for (int i = 0; i < profiles.Count; i++)
+                                        {
+                                            var feature = profiles[i].GetFeaturebyAction(item.OutAction);
+
+                                            if (feature != null)
+                                            {
+                                                _RequestType = feature.GetRequestType();
+                                                break;
+                                            }
+                                        }
+
+                                        if (_RequestType != null && item.CreatedBy != "Destroyer")
+                                        {
+                                            request = JsonConvert.DeserializeObject(item.OutRequest, _RequestType) as IRequest;
+                                            uuid = session.queue.store(request);
+                                            rawRequest = BasicMessageHandler.GenerateRequest(uuid, item.OutAction, request);
+                                            Send(session, rawRequest, string.Format("{0} {1}", action, "Request"), "");
+                                        }
+
+
+                                        if (item.CreatedBy == "Destroyer")
+                                        {
+
+                                            if (_RequestType != null)
+                                            {
+                                                request = Activator.CreateInstance(_RequestType) as IRequest;
+                                                uuid = session.queue.store(request);
+                                                rawRequest = BasicMessageHandler.GenerateDestroyRequest(uuid, item.OutAction, item.OutRequest);
+                                                Send(session, rawRequest, string.Format("{0} {1}", action, "Request"), "");
+
+                                            }
+                                            else
+                                            {
+
+                                                rawRequest = BasicMessageHandler.GenerateDestroyRequest(Guid.NewGuid().ToString(), item.OutAction, item.OutRequest);
+                                                Send(session, rawRequest, string.Format("{0} {1}", action, "Request"), "");
+
+                                            }
+                                        }
+
+                                        AddConfirmMessage(charger_SN, item.Id, item.SerialNo, item.OutAction, uuid, item.CreatedBy, rawRequest);
+
+                                        #region 更新資料表單一欄位
+                                        var _UpdatedItem = new ServerMessage() { Id = item.Id, UpdatedOn = DateTime.UtcNow };
+                                        db.Configuration.AutoDetectChangesEnabled = false;//自動呼叫DetectChanges()比對所有的entry集合的每一個屬性Properties的新舊值
+                                        db.Configuration.ValidateOnSaveEnabled = false;// 因為Entity有些欄位必填,若不避開會有Validate錯誤
+                                                                                       // var _UpdatedItem = db.ServerMessage.Where(x => x.Id == item.Id).FirstOrDefault();
+                                        db.ServerMessage.Attach(_UpdatedItem);
+                                        _UpdatedItem.UpdatedOn = DateTime.UtcNow;
+                                        db.Entry(_UpdatedItem).Property(x => x.UpdatedOn).IsModified = true;// 可以直接使用這方式強制某欄位要更新,只是查詢集合耗效能而己
+
+                                        db.SaveChanges();
+
+                                        #endregion
+
+                                        await Task.Delay(100);
+
+                                    }
+
+                                }
+                            }
+                        }
+
+                    }
+
+                    await Task.Delay(500);
+
+                }
+                catch (Exception ex)
+                {
+                    logger.Error(string.Format("ServerMessageTrigger  Ex:{0}", ex.ToString()));
+                }
+            }
+        }
+
+
+        async private void HeartBeatCheckTrigger()
+        {
+            for (; ; )
+            {
+                if (_ct.IsCancellationRequested)
+                {
+                    break;
+                }
+
+                try
+                {
+                    if (DateTime.UtcNow.Subtract(lastcheckdt).TotalSeconds > 30)
+                    {
+                        lastcheckdt = DateTime.UtcNow;
+                        Stopwatch watch = new Stopwatch();
+                        Dictionary<string, ClientData> _copyClientDic = null;
+                        lock (_lockClientDic)
+                        {
+                            _copyClientDic = new Dictionary<string, ClientData>(clientDic);
+                        }
+
+                        var cdt = DateTime.UtcNow;
+                        var clients = _copyClientDic.Where(x => x.Value.LastActiveTime > cdt.AddSeconds(-120)).Select(x => x.Value).ToList();
+
+                        watch.Start();
+                        foreach (var session in clients)
+                        {
+                            using (var db = new MainDBContext())
+                            {
+                                var machine = new Machine() { Id = session.MachineId };
+                                if (machine != null)
+                                {
+                                    db.Configuration.AutoDetectChangesEnabled = false;
+                                    db.Configuration.ValidateOnSaveEnabled = false;
+                                    db.Machine.Attach(machine);
+                                    machine.HeartbeatUpdatedOn = DateTime.UtcNow;
+                                    machine.ConnectionType = session.UriScheme.Equals("wss") ? 2 : 1;
+                                    db.Entry(machine).Property(x => x.HeartbeatUpdatedOn).IsModified = true;
+                                    db.Entry(machine).Property(x => x.ConnectionType).IsModified = true;
+                                    await db.SaveChangesAsync();
+                                }
+
+                            }
+                        }
+                        watch.Stop();
+                        if (watch.ElapsedMilliseconds / 1000 > 5)
+                        {
+                            logger.Fatal("Update HeartBeatCheckTrigger cost " + watch.ElapsedMilliseconds / 1000 + " seconds.");
+                        }
+                    }
+
+
+                    await Task.Delay(10000);
+                }
+                catch (Exception ex)
+                {
+                    Console.WriteLine("***********************************************************");
+                    logger.Error(string.Format("HeartBeatCheckTrigger  Ex:{0}", ex.ToString()));
+                }
+
+            }
+        }
+
+        async private void ServerWeatherNotificationTrigger()
+        {
+            for (; ; )
+            {
+                if (_ct.IsCancellationRequested)
+                {
+                    break;
+                }
+
+                var min_Interval = (DateTime.UtcNow - _CheckWeatherDt).TotalMinutes;
+
+                if (min_Interval > 30)
+                {
+                    // Console.WriteLine("in...............ServerWeatherNotificationTrigger");
+                    BasicMessageHandler msgAnalyser = new BasicMessageHandler();
+                    Dictionary<string, ClientData> _copyClientDic = null;
+                    lock (_lockClientDic)
+                    {
+                        _copyClientDic = new Dictionary<string, ClientData>(clientDic);
+
+                    }
+                    _CheckWeatherDt = DateTime.UtcNow;
+
+                    var locations = _copyClientDic.Where(x => !string.IsNullOrEmpty(x.Value.StationLocation)).Distinct().Select(x => x.Value.StationLocation).ToList();
+
+                    // Console.WriteLine("in...............ServerWeatherNotificationTrigger");
+                    foreach (var location in locations)
+                    {
+
+                        try
+                        {   //query weather
+                            var httpResult = await httpClient.GetWeather("https://api.weatherapi.com/v1/current.json?key=874346abc0874e69a9423510222201&q=" + location, null, null);
+
+                            string temp = "17";
+                            string weather_code = "1183";
+                            if (httpResult.Status == System.Net.HttpStatusCode.OK)
+                            {
+                                try
+                                {
+                                    var jsonResult = JsonConvert.DeserializeObject(httpResult.Response) as JObject;
+                                    temp = jsonResult["current"]["temp_c"].ToString();
+                                    weather_code = jsonResult["current"]["condition"]["code"].ToString();
+
+
+                                }
+                                catch (Exception ex)
+                                {
+                                    ;
+                                }
+
+                            }
+
+                            #region 台泥氣象Mapping
+                            switch (weather_code)
+                            {
+                                case "1000":
+                                    weather_code = "1";
+                                    break;
+                                case "1003":
+                                case "1006":
+                                case "1009":
+                                    weather_code = "2";
+                                    break;
+                                case "1063":
+                                case "1072":
+                                case "1150":
+                                case "1153":
+                                case "1168":
+                                case "1171":
+                                case "1180":
+                                case "1183":
+                                case "1186":
+                                case "1189":
+                                case "1192":
+                                case "1195":
+                                case "1198":
+                                case "1201":
+                                case "1237":
+                                case "1240":
+                                case "1243":
+                                case "1246":
+                                case "1261":
+                                case "1264":
+                                    weather_code = "3";
+                                    break;
+                                case "1087":
+                                case "1273":
+                                case "1276":
+                                case "1279":
+                                case "1282":
+                                    weather_code = "4";
+                                    break;
+                                case "1066":
+                                case "1069":
+                                case "1114":
+                                case "1117":
+                                case "1204":
+                                case "1207":
+                                case "1210":
+                                case "1213":
+                                case "1216":
+                                case "1219":
+                                case "1222":
+                                case "1225":
+                                case "1249":
+                                case "1252":
+                                case "1255":
+                                case "1258":
+                                    weather_code = "5";
+                                    break;
+                                case "1030":
+                                case "1135":
+                                case "1147":
+                                    weather_code = "2";
+                                    break;
+                                default:
+                                    weather_code = "2";
+                                    break;
+                            }
+                            #endregion
+
+
+                            if (TCCStationDic.ContainsKey(location))
+                            {
+                                TCCStationDic[location].Temperature = (int)double.Parse(temp);
+                                TCCStationDic[location].WeatherID = int.Parse(weather_code);
+                            }
+                            else
+                            {
+                                TCCStationDic.Add(location, new TCCWeatherDto() { WeatherID = int.Parse(weather_code), Temperature = (int)double.Parse(temp) });
+                            }
+
+                        }
+                        catch (Exception ex)
+                        {
+                            logger.Error(string.Format("ServerWeatherNotificationTrigger ChargeBoxId:{0}  Ex:{1}", location, ex.ToString()));
+                        }
+                    }
+
+                    var clients = _copyClientDic.Where(x => x.Value.CustomerId == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8")).
+                    Select(x => new { ChargeBoxId = x.Value.ChargeBoxId, StationLocation = x.Value.StationLocation }).ToList();
+
+                    using (var db = new MainDBContext())
+                    {
+
+                        foreach (var client in clients)
+                        {
+                            try
+                            {
+                                if (string.IsNullOrEmpty(client.StationLocation))
+                                {
+                                    Console.WriteLine(client.StationLocation + " is empty");
+                                    continue;
+                                }
+
+
+                                if (TCCStationDic.ContainsKey(client.StationLocation))
+                                {
+                                    db.ServerMessage.Add(new ServerMessage()
+                                    {
+                                        ChargeBoxId = client.ChargeBoxId,
+                                        CreatedBy = "Server",
+                                        CreatedOn = DateTime.UtcNow,
+                                        OutAction = Actions.DataTransfer.ToString(),
+                                        OutRequest = JsonConvert.SerializeObject(
+                                                           new DataTransferRequest()
+                                                           {
+                                                               messageId = "ID_Weather_Info",
+                                                               vendorId = "Phihong Technology",
+                                                               data = JsonConvert.SerializeObject(
+                                                                   new
+                                                                   {
+                                                                       weatherId = TCCStationDic[client.StationLocation].WeatherID,
+                                                                       Temperature = TCCStationDic[client.StationLocation].Temperature
+                                                                   })
+                                                           },
+                                                           new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                        SerialNo = Guid.NewGuid().ToString(),
+                                        InMessage = string.Empty
+
+                                    });
+
+                                    await db.SaveChangesAsync();
+                                }
+                            }
+                            catch (Exception ex)
+                            {
+                                logger.Error(string.Format("ServerWeatherNotificationTrigger ChargeBoxId:{0}  Ex:{1}", client.ChargeBoxId, ex.ToString()));
+                            }
+
+
+                        }
+                    }
+
+                }
+                await Task.Delay(1000);
+            }
+        }
+
+        async private void ServerSetFeeTrigger()
+        {
+            for (; ; )
+            {
+                if (_ct.IsCancellationRequested)
+                {
+                    break;
+                }
+
+                var min_Interval = (DateTime.UtcNow - _CheckFeeDt).TotalMinutes;
+                if (min_Interval > 1)
+                {
+                    BasicMessageHandler msgAnalyser = new BasicMessageHandler();
+                    Dictionary<string, ClientData> _copyClientDic = null;
+                    lock (_lockClientDic)
+                    {
+                        _copyClientDic = new Dictionary<string, ClientData>(clientDic);
+
+                    }
+                    _CheckFeeDt = DateTime.UtcNow;
+                    foreach (var item in _copyClientDic)
+                    {
+                        try
+                        {
+                            ClientData session = item.Value;
+                            if (session.IsCheckIn)
+                            {
+
+                                string displayPriceText = await SetDefaultFee(session);
+                                if (!string.IsNullOrEmpty(displayPriceText) && displayPriceText != session.DisplayPrice)
+                                {
+                                    clientDic[item.Key].DisplayPrice = displayPriceText;
+
+                                    using (var db = new MainDBContext())
+                                    {
+                                        db.ServerMessage.Add(new ServerMessage()
+                                        {
+                                            ChargeBoxId = session.ChargeBoxId,
+                                            CreatedBy = "Server",
+                                            CreatedOn = DateTime.UtcNow,
+                                            OutAction = Actions.ChangeConfiguration.ToString(),
+                                            OutRequest = JsonConvert.SerializeObject(
+                                                    new ChangeConfigurationRequest()
+                                                    {
+                                                        key = "DefaultPrice",
+                                                        value = clientDic[item.Key].DisplayPrice
+                                                    },
+                                                    new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                            SerialNo = Guid.NewGuid().ToString(),
+                                            InMessage = string.Empty
+
+                                        }); ;
+
+                                        if (session.CustomerId == new Guid("10C7F5BD-C89A-4E2A-8611-B617E0B41A73"))
+                                        {
+                                            db.ServerMessage.Add(new ServerMessage()
+                                            {
+                                                ChargeBoxId = session.ChargeBoxId,
+                                                CreatedBy = "Server",
+                                                CreatedOn = DateTime.UtcNow,
+                                                OutAction = Actions.ChangeConfiguration.ToString(),
+                                                OutRequest = JsonConvert.SerializeObject(
+                                                   new ChangeConfigurationRequest()
+                                                   {
+                                                       key = "ConnectionTimeOut",
+                                                       value = "120"
+                                                   },
+                                                   new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                                SerialNo = Guid.NewGuid().ToString(),
+                                                InMessage = string.Empty
+
+                                            });
+                                            db.ServerMessage.Add(new ServerMessage()
+                                            {
+                                                ChargeBoxId = session.ChargeBoxId,
+                                                CreatedBy = "Server",
+                                                CreatedOn = DateTime.UtcNow,
+                                                OutAction = Actions.ChangeConfiguration.ToString(),
+                                                OutRequest = JsonConvert.SerializeObject(
+                                                   new ChangeConfigurationRequest()
+                                                   {
+                                                       key = "MeterValueSampleInterval",
+                                                       value = "3"
+                                                   },
+                                                   new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                                SerialNo = Guid.NewGuid().ToString(),
+                                                InMessage = string.Empty
+
+                                            });
+                                        }
+
+                                        await db.SaveChangesAsync();
+
+                                    }
+                                }
+                            }
+
+                        }
+                        catch (Exception ex)
+                        {
+                            logger.Error(string.Format("ServerSetFeeTrigger ChargeBoxId:{0}  Ex:{1}", item.Key, ex.ToString()));
+                        }
+                    }
+                }
+                await Task.Delay(1000);
+            }
+        }
+
+        async private Task<string> SetDefaultFee(ClientData client)
+        {
+            string displayPriceText = string.Empty;
+            string charingPriceText = string.Empty;
+
+            if (string.IsNullOrEmpty(client.ChargeBoxId)) return displayPriceText;
+
+            using (SqlConnection conn = new SqlConnection(webConnectionString))
+            {
+                var parameters = new DynamicParameters();
+                parameters.Add("@MachineId", client.MachineId, DbType.String, ParameterDirection.Input);
+                string displayPricestrSql = "";
+                string strSql = "";
+
+                if (client.IsAC)
+                {
+                    displayPricestrSql = "   SELECT  [AC_BillingMethod] as BillingMethod,[AC_FeeName] as FeeName,[AC_Fee] as ChargingFeebyHour" +
+                "  ,[AC_ParkingFee] as ParkingFee, [Currency]  FROM[StationMachine]  left join[dbo].[Station]" +
+                "  on[StationMachine].StationId = Station.[Id]  where StationMachine.MachineId=@MachineId and Station.IsBilling=1; ";
+
+                    strSql = " SELECT CAST( [StartTime] as varchar(5)) StartTime,CAST( [EndTime] as varchar(5)) EndTime,[Fee]  FROM[StationMachine]  left join [dbo].[StationFee]" +
+                   " on[StationMachine].StationId = StationFee.StationId  where StationMachine.MachineId =@MachineId and StationFee.IsAC=1; ";
+                }
+                else
+                {
+                    displayPricestrSql = "   SELECT  [DC_BillingMethod] as BillingMethod,[DC_FeeName] as FeeName,[DC_Fee] as ChargingFeebyHour" +
+               "  ,[DC_ParkingFee] as ParkingFee, [Currency]  FROM[StationMachine]  left join[dbo].[Station]" +
+               "  on[StationMachine].StationId = Station.[Id]  where StationMachine.MachineId=@MachineId and Station.IsBilling=1; ";
+
+                    strSql = " SELECT CAST( [StartTime] as varchar(5)) StartTime,CAST( [EndTime] as varchar(5)) EndTime,[Fee]  FROM[StationMachine]  left join [dbo].[StationFee]" +
+                   " on[StationMachine].StationId = StationFee.StationId  where StationMachine.MachineId =@MachineId and StationFee.IsAC=0; ";
+
+                }
+                var result = await conn.QueryAsync<StationFee>(displayPricestrSql, parameters);
+                if (result.Count() == 0)
+                {
+                    return string.Empty;
+                }
+                var stationPrice = result.First();
+
+                if (stationPrice.BillingMethod == 1)
+                {
+                    var chargingPriceResult = await conn.QueryAsync<ChargingPrice>(strSql, parameters);
+                    client.ChargingPrices = chargingPriceResult.ToList();
+                    if (string.IsNullOrEmpty(client.ChargingPrices[0].StartTime))
+                    {
+                        client.ChargingPrices = new List<ChargingPrice>();
+                    }
+                }
+
+                displayPriceText = stationPrice.FeeName;
+                client.BillingMethod = stationPrice.BillingMethod;
+                client.Currency = stationPrice.Currency;
+                client.ChargingFeebyHour = stationPrice.ChargingFeebyHour;
+                client.ParkingFee = stationPrice.ParkingFee;
+                client.IsBilling = true;
+            }
+
+            return displayPriceText;
+        }
+
+        async private void HealthCheckTrigger()
+        {
+            for (; ; )
+            {
+                if (_ct.IsCancellationRequested)
+                {
+                    break;
+                }
+
+                try
+                {
+                    Dictionary<string, ClientData> _copyClientDic = null;
+                    lock (_lockClientDic)
+                    {
+                        _copyClientDic = new Dictionary<string, ClientData>(clientDic);
+                    }
+
+                    var removeClients = _copyClientDic.Where(x => x.Value.LastActiveTime < DateTime.UtcNow.AddSeconds(-300)).Select(x => x.Value).ToList();
+
+                    foreach (var session in removeClients)
+                    {
+
+                        Console.WriteLine(string.Format("Server forced to shut down ChargeBox ({0}: LastActiveTime{1})", session.ChargeBoxId, session.LastActiveTime));
+                        RemoveClient(session);
+                    }
+
+                    await Task.Delay(60000);
+                }
+                catch (Exception ex)
+                {
+                    logger.Error(string.Format("HealthAlarmTrigger  Ex:{0}", ex.ToString()));
+                }
+
+            }
+        }
+
+
+        private List<NeedConfirmMessage> GetResendMessage()
+        {
+            List<NeedConfirmMessage> sendMessages = new List<NeedConfirmMessage>();
+            lock (_lockConfirmPacketList)
+            {
+                sendMessages = needConfirmPacketList.Where(x => x.SentTimes > 1 && x.CreatedBy == "Server").ToList();
+
+            }
+
+            return sendMessages;
+        }
+
+        private void AddConfirmMessage(string chargePointSerialNumber, int table_id, string requestId, string action, string msg_id, string createdBy, string sendMessage)
+        {
+            NeedConfirmMessage _needConfirmMsg = new NeedConfirmMessage();
+            _needConfirmMsg.Id = table_id;
+            _needConfirmMsg.SentAction = action;
+            _needConfirmMsg.SentOn = DateTime.UtcNow;
+            _needConfirmMsg.SentTimes = 4;
+            _needConfirmMsg.ChargePointSerialNumber = chargePointSerialNumber;
+            _needConfirmMsg.RequestId = requestId;
+            _needConfirmMsg.SentUniqueId = msg_id;
+            _needConfirmMsg.CreatedBy = createdBy;
+            _needConfirmMsg.SentMessage = sendMessage;
+
+            if (needConfirmActions.Contains(action))
+            {
+
+                lock (_lockConfirmPacketList)
+                {
+                    needConfirmPacketList.Add(_needConfirmMsg);
+                }
+            }
+        }
+
+        private void RemoveConfirmMessage()
+        {
+            var before10Mins = DateTime.UtcNow.AddMinutes(-10);
+            lock (_lockConfirmPacketList)
+            {
+                var removeList = needConfirmPacketList.Where(x => x.SentTimes == 0 || x.SentOn < before10Mins).ToList();
+                foreach (var item in removeList)
+                {
+                    needConfirmPacketList.Remove(item);
+                }
+            }
+        }
+
+        private bool ReConfirmMessage(MessageResult analysisResult)
+        {
+            bool confirmed = false;
+            if (needConfirmActions.Contains(analysisResult.Action))
+            {
+
+                NeedConfirmMessage foundRequest = null;
+                lock (_lockConfirmPacketList)
+                {
+                    foundRequest = needConfirmPacketList.Where(x => x.SentUniqueId == analysisResult.UUID).FirstOrDefault();
+                }
+
+                if (foundRequest != null && foundRequest.Id > 0)
+                {
+                    foundRequest.SentTimes = 0;
+                    foundRequest.SentInterval = 0;
+                    analysisResult.RequestId = foundRequest.RequestId;
+
+                    using (var db = new MainDBContext())
+                    {
+                        var sc = db.ServerMessage.Where(x => x.Id == foundRequest.Id).FirstOrDefault();
+                        sc.InMessage = JsonConvert.SerializeObject(analysisResult.Message, Formatting.None);
+                        sc.ReceivedOn = DateTime.UtcNow;
+                        db.SaveChanges();
+                        //  Console.WriteLine(string.Format("Now:{0} ServerMessage Id:{1} ", DateTime.UtcNow.ToString("yyyy/MM/dd HH:mm:ss"), foundRequest.Id));
+
+                    }
+                    confirmed = true;
+
+
+
+                }
+                else if (analysisResult.Action == Actions.TriggerMessage.ToString())
+                {
+                    confirmed = true;
+                }
+                else
+                {
+                    logger.Error(string.Format("Received no record Action:{0} MessageId:{1} ", analysisResult.Action, analysisResult.UUID));
+                }
+            }
+
+            return confirmed;
+        }
+
+
+
+
+        private void RemoveClient(ClientData session)
+        {
+
+
+            if (session != null)
+            {
+
+                if (!string.IsNullOrEmpty(session.MachineId))
+                    logger.Trace("RemoveClient[" + session.ChargeBoxId + "]");
+
+                if (session.Connected)
+                {
+                    session.Close(CloseReason.ServerShutdown);
+                }
+                RemoveClientDic(session);
+                try
+                {
+                    session.m_ReceiveData -= new ClientData.OCPPClientDataEventHandler<ClientData, String>(ReceivedMessage);
+                    // session.Close(CloseReason.ServerShutdown);
+
+                }
+                catch (Exception ex)
+                {
+                    //logger.Warn("Close client socket error!!");
+                    logger.Warn(string.Format("Close client socket error!! {0} Msg:{1}", session.ChargeBoxId, ex.Message));
+                }
+
+                if (session != null)
+                {
+                    session = null;
+                }
+
+            }
+        }
+
+        private void RemoveClientDic(ClientData session)
+        {
+            if (!string.IsNullOrEmpty(session.ChargeBoxId))
+            {
+                lock (_lockClientDic)
+                {
+
+                    if (clientDic.ContainsKey(session.ChargeBoxId))
+                    {
+                        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);
+                        }
+
+                    }
+                }
+            }
+
+        }
+
+        private void WarmUpLog()
+        {
+            try
+            {
+                using (var log = new ConnectionLogDBContext())
+                {
+                    log.MachineConnectionLog.ToList();
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.ToString());
+            }
+
+
+        }
+
+        private void WriteMachineLog(ClientData clientData, string data, string messageType, string errorMsg = "", bool isSent = false)
+        {
+            try
+            {
+
+                if (clientData == null || string.IsNullOrEmpty(data)) return;
+
+                if (clientData.ChargeBoxId == null)
+                {
+                    logger.Fatal(clientData.Path + "]********************session ChargeBoxId null sessionId=" + clientData.SessionID);
+                }
+                using (var db = new ConnectionLogDBContext())
+                {
+                    string sp = "[dbo].[uspInsertMachineConnectionLog] @CreatedOn," +
+                          "@ChargeBoxId,@MessageType,@Data,@Msg,@IsSent,@EVSEEndPoint,@Session";
+                    var dd = DateTime.UtcNow;
+                    SqlParameter[] parameter =
+                    {
+                      new SqlParameter("CreatedOn",dd),
+                      new SqlParameter("ChargeBoxId",clientData.ChargeBoxId==null?"unknown":clientData.ChargeBoxId.Replace("'","''")),
+                      new SqlParameter("MessageType",messageType.Replace("'","''")),
+                      new SqlParameter("Data",data.Replace("'","''")),
+                      new SqlParameter("Msg",errorMsg.Replace("'","''")),
+                      new  SqlParameter("IsSent",isSent),
+                      new  SqlParameter("EVSEEndPoint",clientData.RemoteEndPoint==null?"123":clientData.RemoteEndPoint.ToString()),
+                      new  SqlParameter("Session",clientData.SessionID==null?"123":clientData.SessionID)
+               };
+
+                    db.Database.ExecuteSqlCommand(sp, parameter);
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.ToString());
+            }
+
+
+        }
+    }
+}

+ 93 - 136
EVCB_OCPP.WSServer/Service/LoadingBalanceService.cs

@@ -6,6 +6,7 @@ using System.Configuration;
 using System.Data;
 using System.Data.SqlClient;
 using System.Linq;
+using System.Threading.Tasks;
 
 namespace EVCB_OCPP.WSServer.Service
 {
@@ -46,9 +47,9 @@ namespace EVCB_OCPP.WSServer.Service
         }
 
 
-        public bool IsNeedtoCancelSetting(int stationId, string machineId, string chargeBoxId)
+        async public Task<bool> IsNeedtoCancelSetting(int stationId, string machineId, string chargeBoxId)
         {
-            var setting = GetLoadBalance(stationId);
+            var setting = await GetLoadBalance(stationId);
             if (setting == null) return false;
 
             lock (GetLock(stationId))
@@ -56,14 +57,14 @@ namespace EVCB_OCPP.WSServer.Service
                 if (setting.LBMode > 0 && setting.LBMode < 3 && !IsStillInTransactions(chargeBoxId))
                 {
                     // renew table
-                    UpdateLoadbalanceRecord(stationId, machineId, 0, DateTime.UtcNow);
+                //    UpdateLoadbalanceRecord(stationId, machineId, 0, DateTime.UtcNow);
                     return true;
 
                 }
 
                 if (setting.LBMode >= 3 || setting.LBMode < 1)
                 {
-                    CloseLoadbalanceRecord(stationId);
+                 //   CloseLoadbalanceRecord(stationId);
 
                 }
             }
@@ -174,65 +175,12 @@ namespace EVCB_OCPP.WSServer.Service
 
 
 
-        public Dictionary<string, decimal?> GetRerangeSettingPower(int stationId)
-        {
-            Dictionary<string, decimal?> dic = new Dictionary<string, decimal?>();
-            var setting = GetLoadBalance(stationId);
-            if (setting == null) return null;
-
-            lock (GetLock(stationId))
-            {
-                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)
+        async public Task<Dictionary<string, decimal?>> GetSettingPower(int stationId)
         {
             Dictionary<string, decimal?> dic = new Dictionary<string, decimal?>();
-            var setting = GetLoadBalance(stationId);
+            var setting = await GetLoadBalance(stationId);
             if (setting == null) return null;
 
             lock (GetLock(stationId))
@@ -242,31 +190,9 @@ namespace EVCB_OCPP.WSServer.Service
                 {
                     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);
-                            }
-
-                        }
+                        dic = GetAveragePower(stationId, setting.LBCurrent).Result;
                     }
-                    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);
-
-                    }
                 }
 
             }
@@ -275,7 +201,7 @@ namespace EVCB_OCPP.WSServer.Service
         }
 
 
-        public LoadBalanceSetting GetLoadBalance(int stationId)
+        async public Task<LoadBalanceSetting> GetLoadBalance(int stationId)
         {
             LoadBalanceSetting setting = null;
             using (SqlConnection conn = new SqlConnection(webConnectionString))
@@ -284,12 +210,13 @@ namespace EVCB_OCPP.WSServer.Service
                 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();
+                var result = await conn.QueryAsync<LoadBalanceSetting>(strSql, parameters);
+                setting = result.FirstOrDefault();
             }
             return setting;
         }
 
-        private List<string> GetIdsbyStationId(int stationId)
+        async private Task<List<string>> GetIdsbyStationId(int stationId)
         {
             List<string> machineIds = new List<string>();
             using (SqlConnection conn = new SqlConnection(webConnectionString))
@@ -297,97 +224,127 @@ namespace EVCB_OCPP.WSServer.Service
                 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();
+                var result = await conn.QueryAsync<String>(strSql, parameters);
+                machineIds = result.ToList();
             }
             return machineIds;
         }
 
 
 
-        private Dictionary<string, decimal?> GetAveragePower(int stationId, int availableCapacity, string machineId = "")
+        async private Task<Dictionary<string, decimal?>> GetAveragePower(int stationId, int availableCapacity)
         {
             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))
+            availableCapacity = (int)(availableCapacity * 1000 / 1.05M);
+            int keepPower = 0;
+            //讀取上一次斷線但還沒充完電的分配量
+            var offlineCPs = GetChargeBoxIdbyOfflineCharging(stationId, out keepPower);
+            //扣除Keep充電功率  =  分配充電量
+            var totalPower = availableCapacity - keepPower;
+
+            if (totalPower > 0)
             {
-                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();
-            }
+                //總量 * 該樁的額定功率/該站充電中樁的總額定功率
+                var onlineChargingCPs = await GetOnlineChargerwithCharging(stationId);
+                if (onlineChargingCPs.Count > 0)
+                {
+                    int singlePower = (int)Decimal.Divide(totalPower, onlineChargingCPs.Count);
+
+                    foreach (var id in onlineChargingCPs)
+                    {
+                        dic.Add(id, singlePower);
+                    }
+                }
 
-            if (!string.IsNullOrEmpty(machineId) && !_MachineIds.Contains(machineId))
-            {
-                _MachineIds.Add(machineId);
             }
 
-            while (skipCount < _MachineIds.Count())
-            {
-                takeCount = _MachineIds.Count() - skipCount > size ? size : _MachineIds.Count() - skipCount;
+            return dic;
 
-                using (SqlConnection conn = new SqlConnection(mainConnectionString))
+        }
+
+        async private Task<List<string>> GetOnlineChargerwithCharging(int stationId)
+        {
+            List<string> results = new List<string>();
+            List<string> machineIds = await GetIdsbyStationId(stationId);
+            List<string> chargeboxids = new List<string>();
+            using (SqlConnection conn = new SqlConnection(mainConnectionString))
+            {
+                string onlineChargerSql = "Select ChargeBoxId from [dbo].[Machine] where Id in @machineIds and [Online]=1; ";
+                var onlineResult = await conn.QueryAsync<string>(onlineChargerSql, new { machineIds = machineIds.ToArray() });
+                chargeboxids = onlineResult.ToList();
+                foreach (var chargeboxid in chargeboxids)
                 {
-                    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;
+                    string txSql = "SELECT TOP(1) [Id] from [dbo].[TransactionRecord] where ChargeBoxId=@ChargeBoxId and StopTime = '1991-01-01 00:00:00.000'; ";
+                    var txId = await conn.ExecuteScalarAsync<Int64>(txSql, new { ChargeBoxId = chargeboxid });
+                    if (txId > 0)
+                    {
+                        results.Add(chargeboxid);
+                    }
                 }
-            }
 
-            foreach (var id in _MachineIds)
-            {
-                int singleRatePower = (int)GetRatedPower(id);
-                var value = totalRatePower == 0 ? 0 : availableCapacity * singleRatePower / totalRatePower;
-                dic.Add(id, value);
             }
+            return results;
+        }
 
-            return dic;
+        /// <summary>
+        /// 取得斷線樁號
+        /// </summary>
+        /// <param name="stationId">站點代號</param>
+        /// <param name="ratedPowers">總額定功率</param>
+        /// <returns></returns>
+        private List<string> GetChargeBoxIdbyOfflineCharging(int stationId, out int ratedPowers)
+        {
+            List<string> machineIds = GetIdsbyStationId(stationId).Result;
+            List<string> result = new List<string>();
+            ratedPowers = 0;
+            using (SqlConnection conn = new SqlConnection(mainConnectionString))
+            {
 
+                string offlineChargerSql = "Select ChargeBoxId from [dbo].[Machine] where Id in @machineIds and [Online]=0; ";
+                result = conn.Query<string>(offlineChargerSql, new { machineIds = machineIds }).ToList();
+                foreach (var charger in result)
+                {
+                    string txSql = "SELECT TOP(1) [Id] from [dbo].[TransactionRecord] where ChargeBoxId=@ChargeBoxId and StopTime = '1991-01-01 00:00:00.000'; ";
+                    var txId = conn.ExecuteScalar<Int64>(txSql, new { ChargeBoxId = charger });
+                    if (txId > 0)
+                    {
+                        string ratedPowerSql = "Select Sum(RatedPower) from [dbo].[Machine] where ChargeBoxId=@ChargeBoxId and [Online]=0; ";
+                        ratedPowers += conn.ExecuteScalar<int>(ratedPowerSql, new { ChargeBoxId = charger });
+                    }
+                }
+            }
+            ratedPowers *= 1000;
+            return result;
         }
 
-        private decimal GetRatedPower(string machineId)
+        private decimal GetRatedPowerbyChargeBoxId(string chargeBoxId)
         {
             decimal ratedPower = 0;
             using (SqlConnection conn = new SqlConnection(mainConnectionString))
             {
                 var parameters = new DynamicParameters();
-                parameters.Add("@machineId", machineId, DbType.String, ParameterDirection.Input);
+                parameters.Add("@machineId", chargeBoxId, 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)
+        private decimal GetRatedPowerbyId(string machineId)
         {
-
-            decimal ongoingPower = 0;
-            decimal singleRatePower = GetRatedPower(machineId);
-
-            //先找LB 裡面目前下發的Power
-            decimal? currentPower = GetCurrentSetting(machineId);
-
-            if (!currentPower.HasValue) currentPower = 0;
-
-            //總量 - 所有正在進行的Power
+            decimal ratedPower = 0;
             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);
+                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 availableCapacity - (ongoingPower - currentPower.Value) > singleRatePower ? singleRatePower :
-                (availableCapacity - (ongoingPower - currentPower.Value) > 0 ? availableCapacity - (ongoingPower - currentPower.Value) : 0);
+            return ratedPower;
         }
 
 
+
     }
 }
 

+ 393 - 0
EVCB_OCPP.WSServer/Service/LoadingBalanceService.cs.bak

@@ -0,0 +1,393 @@
+using Dapper;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Data.SqlClient;
+using System.Linq;
+
+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;
+
+        ConcurrentDictionary<int, object> _lockDic = new ConcurrentDictionary<int, object>();
+
+
+        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;
+
+            lock (GetLock(stationId))
+            {
+                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 object GetLock(int stationId)
+        {
+
+            if (!_lockDic.ContainsKey(stationId))
+            {
+                _lockDic.TryAdd(stationId, new object());
+            }
+
+            return _lockDic[stationId];
+
+        }
+        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;
+
+            lock (GetLock(stationId))
+            {
+                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;
+
+            lock (GetLock(stationId))
+            {
+
+                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 - 4
EVCB_OCPP.WSServer/SuperSocket.Protocol/ClientData.cs

@@ -16,7 +16,7 @@ namespace OCPPServer.Protocol
 
         public EVCB_OCPP20.Packet.Messages.Basic.Queue queue20 = new EVCB_OCPP20.Packet.Messages.Basic.Queue();
 
-        public bool IsPending { set; get; }
+        public bool? IsPending { set; get; }
         public bool IsCheckIn { set; get; }
 
         public string ChargeBoxId { set; get; }
@@ -76,10 +76,10 @@ namespace OCPPServer.Protocol
         public string CustomerName { get; set; }
 
 
-        public string StationName { set; get; }
+        public string StationId { set; get; }
 
 
-        public string StationLocation { set; get; }
+      
 
         public delegate void OCPPClientDataEventHandler<ClientData, String>(ClientData clientdata, String msg);
 
@@ -88,7 +88,7 @@ namespace OCPPServer.Protocol
         public ClientData()
         {
             IsAC = true;
-            IsPending = false;
+          
             IsCheckIn = false;
             ChargeBoxId = SessionID;
             MachineId = SessionID;

+ 128 - 0
EVCB_OCPP.WSServer/SuperSocket.Protocol/ClientData.cs.bak

@@ -0,0 +1,128 @@
+
+using EVCB_OCPP.Packet.Messages.Basic;
+using EVCB_OCPP.WSServer.Dto;
+using SuperSocket.SocketBase;
+using SuperWebSocket;
+using System;
+using System.Collections.Generic;
+
+namespace OCPPServer.Protocol
+{
+    public class ClientData : WebSocketSession<ClientData>
+    { /// <summary>
+      /// 根據unique id來儲存.取出OCPP Request
+      /// </summary>
+        public Queue queue = new Queue();
+
+        public EVCB_OCPP20.Packet.Messages.Basic.Queue queue20 = new EVCB_OCPP20.Packet.Messages.Basic.Queue();
+
+        public bool IsPending { set; get; }
+        public bool IsCheckIn { set; get; }
+
+        public string ChargeBoxId { set; get; }
+
+        public Guid CustomerId { get; set; }
+
+        public string MachineId { set; get; }
+
+        public bool ISOCPP20 { set; get; }
+
+        public bool ResetSecurityProfile { set; get; }
+
+
+        public bool IsAC { set; get; }
+
+        #region Billing
+
+        public Dictionary<string,string> UserPrices { set; get; }
+
+        public Dictionary<string, string> UserDisplayPrices { set; get; }
+
+        public List<ChargingPrice> ChargingPrices { set; get; }
+
+        /// <summary>
+        /// 電樁顯示費率
+        /// </summary>
+        public string DisplayPrice { set; get; }
+
+        /// <summary>
+        /// 充電費率 以小時計費
+        /// </summary>
+        public decimal ChargingFeebyHour { set; get; }
+
+        /// <summary>
+        /// 停車費率 以小時計費
+        /// </summary>
+        public decimal ParkingFee { set; get; }
+
+        /// <summary>
+        /// 電樁是否計費
+        /// </summary>
+        public bool IsBilling { set; get; }
+
+        /// <summary>
+        /// 收費方式 1: 以度計費 2:以小時計費
+        /// </summary>
+        public int BillingMethod { set; get; }
+       
+
+        /// <summary>
+        /// 電樁適用幣別
+        /// </summary>
+        public string Currency { get; internal set; }
+
+        #endregion
+
+        public string CustomerName { get; set; }
+
+
+        public string StationName { set; get; }
+
+
+        public string StationLocation { set; get; }
+
+        public delegate void OCPPClientDataEventHandler<ClientData, String>(ClientData clientdata, String msg);
+
+        public event OCPPClientDataEventHandler<ClientData, String> m_ReceiveData;
+
+        public ClientData()
+        {
+            IsAC = true;
+            IsPending = false;
+            IsCheckIn = false;
+            ChargeBoxId = SessionID;
+            MachineId = SessionID;
+            UserPrices = new Dictionary<string, string>();
+            UserDisplayPrices = new Dictionary<string, string>();
+        }
+
+
+
+        /// <summary>
+        /// Sends the raw binary data to client.
+        /// </summary>
+        /// <param name="data">The data.</param>
+        /// <param name="offset">The offset.</param>
+        /// <param name="length">The length.</param>
+        public void SendRawData(byte[] data, int offset, int length)
+        {
+            base.Send(data, offset, length);
+        }
+
+        //receive data event trigger
+        public void ReceiveData(ClientData clientdata, string msg)
+        {
+            if (m_ReceiveData != null)
+                m_ReceiveData(clientdata, msg);
+        }
+
+        /// <summary>
+        /// Called when [session closed].
+        /// </summary>
+        /// <param name="reason">The reason.</param>
+        protected override void OnSessionClosed(CloseReason reason)
+        {
+        }
+
+    }
+}

+ 23 - 0
EVCB_OCPP.WSServer/SuperSocket.Protocol/OCPPWSServer.cs

@@ -1,5 +1,6 @@
 
 using EVCB_OCPP.Domain;
+using EVCB_OCPP.WSServer;
 using NLog;
 using OCPPPackage.Profiles;
 using SuperWebSocket;
@@ -78,6 +79,28 @@ namespace OCPPServer.Protocol
 
             string[] words = session.Path.Split('/');
             session.ChargeBoxId = words.Last();
+           
+            foreach(var denyModel in GlobalConfig.DenyModelNames)
+            {
+                if (string.IsNullOrEmpty(denyModel)) break;
+                if (session.ChargeBoxId.StartsWith(denyModel))
+                {                 
+
+                    StringBuilder responseBuilder = new StringBuilder();
+
+                    responseBuilder.AppendFormatWithCrCf(@"HTTP/{0} {1} {2}", "1.1",
+                    (int)HttpStatusCode.Unauthorized, @"Unauthorized");
+
+                    responseBuilder.AppendWithCrCf();
+                    string sb = responseBuilder.ToString();
+                    byte[] data = Encoding.UTF8.GetBytes(sb);
+
+                    ((IWebSocketSession)session).SendRawData(data, 0, data.Length);
+                    logger.Info(sb);
+                    return false;
+                }
+            }
+
 
             if (ConfigurationManager.AppSettings["MaintainMode"] == "1")
             {

BIN
SuperWebSocket/bin/Debug/SuperWebSocket.dll


BIN
SuperWebSocket/bin/Debug/SuperWebSocket.pdb


BIN
TestTool.RemoteTriggerAPP/DLL/EVCB_OCPP.Domain.dll