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; using System.Threading.Tasks; namespace EVCB_OCPP.WSServer.Service { public class LoadBalanceSetting { public int StationId { set; get; } public int LBMode { set; get; } public int LBCurrent { set; get; } } public class LoadingBalanceService { string mainConnectionString = ConfigurationManager.ConnectionStrings["MainDBContext"].ConnectionString; string webConnectionString = ConfigurationManager.ConnectionStrings["WebDBContext"].ConnectionString; ConcurrentDictionary _lockDic = new ConcurrentDictionary(); 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(strSql, parameters); } return stationId; } async public Task IsNeedtoCancelSetting(int stationId, string machineId, string chargeBoxId) { var setting = await 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(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(strSql, parameters); } return result; } async public Task> GetSettingPower(int stationId) { Dictionary dic = new Dictionary(); var setting = await GetLoadBalance(stationId); if (setting == null) return null; lock (GetLock(stationId)) { if (setting != null) { if (setting.LBMode == 1) { dic = GetAveragePower(stationId, setting.LBCurrent).Result; } } } return dic; } async public Task 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 ; "; var result = await conn.QueryAsync(strSql, parameters); setting = result.FirstOrDefault(); } return setting; } async private Task> GetIdsbyStationId(int stationId) { List machineIds = new List(); 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; "; var result = await conn.QueryAsync(strSql, parameters); machineIds = result.ToList(); } return machineIds; } async private Task> GetAveragePower(int stationId, int availableCapacity) { Dictionary dic = new Dictionary(); availableCapacity = (int)(availableCapacity * 1000 / 1.05M); int keepPower = 0; //讀取上一次斷線但還沒充完電的分配量 var offlineCPs = GetChargeBoxIdbyOfflineCharging(stationId, out keepPower); //扣除Keep充電功率 = 分配充電量 var totalPower = availableCapacity - keepPower; if (totalPower > 0) { //總量 * 該樁的額定功率/該站充電中樁的總額定功率 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); } } } return dic; } async private Task> GetOnlineChargerwithCharging(int stationId) { List results = new List(); List machineIds = await GetIdsbyStationId(stationId); List chargeboxids = new List(); 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(onlineChargerSql, new { machineIds = machineIds.ToArray() }); chargeboxids = onlineResult.ToList(); foreach (var chargeboxid in chargeboxids) { 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(txSql, new { ChargeBoxId = chargeboxid }); if (txId > 0) { results.Add(chargeboxid); } } } return results; } /// /// 取得斷線樁號 /// /// 站點代號 /// 總額定功率 /// private List GetChargeBoxIdbyOfflineCharging(int stationId, out int ratedPowers) { List machineIds = GetIdsbyStationId(stationId).Result; List result = new List(); 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(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(txSql, new { ChargeBoxId = charger }); if (txId > 0) { string ratedPowerSql = "Select Sum(RatedPower) from [dbo].[Machine] where ChargeBoxId=@ChargeBoxId and [Online]=0; "; ratedPowers += conn.ExecuteScalar(ratedPowerSql, new { ChargeBoxId = charger }); } } } ratedPowers *= 1000; return result; } private decimal GetRatedPowerbyChargeBoxId(string chargeBoxId) { decimal ratedPower = 0; using (SqlConnection conn = new SqlConnection(mainConnectionString)) { var parameters = new DynamicParameters(); parameters.Add("@machineId", chargeBoxId, DbType.String, ParameterDirection.Input); string strSql = "Select RatedPower from [dbo].[Machine] where Id=@machineId; "; ratedPower = conn.ExecuteScalar(strSql, parameters); } return ratedPower; } private decimal GetRatedPowerbyId(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(strSql, parameters); } return ratedPower; } } }