LoadingBalanceService.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. using Dapper;
  2. using System;
  3. using System.Collections.Concurrent;
  4. using System.Collections.Generic;
  5. using System.Configuration;
  6. using System.Data;
  7. using System.Data.SqlClient;
  8. using System.Linq;
  9. namespace EVCB_OCPP.WSServer.Service
  10. {
  11. public class LoadBalanceSetting
  12. {
  13. public int StationId { set; get; }
  14. public int LBMode { set; get; }
  15. public int LBCurrent { set; get; }
  16. }
  17. public class LoadingBalanceService
  18. {
  19. string mainConnectionString = ConfigurationManager.ConnectionStrings["MainDBContext"].ConnectionString;
  20. string webConnectionString = ConfigurationManager.ConnectionStrings["WebDBContext"].ConnectionString;
  21. ConcurrentDictionary<int, object> _lockDic = new ConcurrentDictionary<int, object>();
  22. public LoadingBalanceService()
  23. {
  24. }
  25. public int GetStationIdByMachineId(string machineId)
  26. {
  27. int stationId = 0;
  28. using (SqlConnection conn = new SqlConnection(webConnectionString))
  29. {
  30. var parameters = new DynamicParameters();
  31. parameters.Add("@MachineId", machineId, DbType.String, ParameterDirection.Input);
  32. string strSql = "Select StationId from [dbo].[StationMachine] where MachineId=@MachineId ; ";
  33. stationId = conn.ExecuteScalar<Int32>(strSql, parameters);
  34. }
  35. return stationId;
  36. }
  37. public bool IsNeedtoCancelSetting(int stationId, string machineId, string chargeBoxId)
  38. {
  39. var setting = GetLoadBalance(stationId);
  40. if (setting == null) return false;
  41. lock (GetLock(stationId))
  42. {
  43. if (setting.LBMode > 0 && setting.LBMode < 3 && !IsStillInTransactions(chargeBoxId))
  44. {
  45. // renew table
  46. UpdateLoadbalanceRecord(stationId, machineId, 0, DateTime.UtcNow);
  47. return true;
  48. }
  49. if (setting.LBMode >= 3 || setting.LBMode < 1)
  50. {
  51. CloseLoadbalanceRecord(stationId);
  52. }
  53. }
  54. return false;
  55. }
  56. private object GetLock(int stationId)
  57. {
  58. if (!_lockDic.ContainsKey(stationId))
  59. {
  60. _lockDic.TryAdd(stationId, new object());
  61. }
  62. return _lockDic[stationId];
  63. }
  64. private void CloseLoadbalanceRecord(int stationId)
  65. {
  66. using (SqlConnection conn = new SqlConnection(mainConnectionString))
  67. {
  68. var parameters = new DynamicParameters();
  69. parameters.Add("@StationId", stationId, DbType.Int32, ParameterDirection.Input);
  70. parameters.Add("@FinishedOn", DateTime.UtcNow, DbType.DateTime, ParameterDirection.Input);
  71. string strSql = "Update [dbo].[LoadingBalance] SET FinishedOn=@FinishedOn where StationId=@StationId and FinishedOn='1991/01/01'; ";
  72. conn.Execute(strSql, parameters);
  73. }
  74. }
  75. private void UpdateLoadbalanceRecord(int stationId, string machineId, decimal power, DateTime? finishedOn, bool keepgoing = false)
  76. {
  77. using (SqlConnection conn = new SqlConnection(mainConnectionString))
  78. {
  79. if (finishedOn.HasValue)
  80. {
  81. var parameters = new DynamicParameters();
  82. parameters.Add("@MachineId", machineId, DbType.String, ParameterDirection.Input);
  83. parameters.Add("@FinishedOn", finishedOn.Value, DbType.DateTime, ParameterDirection.Input);
  84. string strSql = "Update [dbo].[LoadingBalance] SET FinishedOn=@FinishedOn where MachineId=@MachineId and FinishedOn='1991/01/01'; ";
  85. conn.Execute(strSql, parameters);
  86. }
  87. else
  88. {
  89. if (keepgoing)
  90. {
  91. var parameters = new DynamicParameters();
  92. parameters.Add("@MachineId", machineId, DbType.String, ParameterDirection.Input);
  93. parameters.Add("@Power", power, DbType.Decimal, ParameterDirection.Input);
  94. string strSql = "Update [dbo].[LoadingBalance] SET Power=@Power where MachineId=@MachineId and FinishedOn='1991/01/01'; ";
  95. conn.Execute(strSql, parameters);
  96. }
  97. else
  98. {
  99. var parameters = new DynamicParameters();
  100. parameters.Add("@StationId", stationId, DbType.Int32, ParameterDirection.Input);
  101. parameters.Add("@MachineId", machineId, DbType.String, ParameterDirection.Input);
  102. parameters.Add("@Power", power, DbType.Decimal, ParameterDirection.Input);
  103. parameters.Add("@CreatedOn", DateTime.UtcNow, DbType.DateTime, ParameterDirection.Input);
  104. parameters.Add("@FinishedOn", new DateTime(1991, 1, 1, 0, 0, 0, DateTimeKind.Utc), DbType.DateTime, ParameterDirection.Input);
  105. string strSql = "INSERT INTO [dbo].[LoadingBalance] " +
  106. "([StationId],[MachineId],[Power],[CreatedOn],[FinishedOn]) " +
  107. "VALUES(@StationId,@MachineId,@Power,@CreatedOn,@FinishedOn);";
  108. conn.Execute(strSql, parameters);
  109. }
  110. }
  111. }
  112. }
  113. private bool IsStillInTransactions(string chargeBoxId)
  114. {
  115. bool result = false;
  116. using (SqlConnection conn = new SqlConnection(mainConnectionString))
  117. {
  118. var parameters = new DynamicParameters();
  119. parameters.Add("@ChargeBoxId", chargeBoxId, DbType.String, ParameterDirection.Input);
  120. string strSql = "Select count(*) from [dbo].[TransactionRecord] where ChargeBoxId=@ChargeBoxId and StopTime='1991/01/01'; ";
  121. result = conn.ExecuteScalar<bool>(strSql, parameters);
  122. }
  123. return result;
  124. }
  125. private decimal? GetCurrentSetting(string machineId)
  126. {
  127. decimal? result = (decimal?)null;
  128. using (SqlConnection conn = new SqlConnection(mainConnectionString))
  129. {
  130. var parameters = new DynamicParameters();
  131. parameters.Add("@MachineId", machineId, DbType.String, ParameterDirection.Input);
  132. string strSql = "Select Power from [dbo].[LoadingBalance] where MachineId=@MachineId and FinishedOn='1991/01/01'; ";
  133. result = conn.ExecuteScalar<decimal>(strSql, parameters);
  134. }
  135. return result;
  136. }
  137. public Dictionary<string, decimal?> GetRerangeSettingPower(int stationId)
  138. {
  139. Dictionary<string, decimal?> dic = new Dictionary<string, decimal?>();
  140. var setting = GetLoadBalance(stationId);
  141. if (setting == null) return null;
  142. lock (GetLock(stationId))
  143. {
  144. if (setting != null && setting.LBMode == 2)
  145. {
  146. string machineId = string.Empty;
  147. decimal ratedPower = GetRatedPower(machineId);
  148. //找站內最早要充電的交易 下發充電Power & 填寫新給的Power
  149. using (SqlConnection conn = new SqlConnection(mainConnectionString))
  150. {
  151. var parameters = new DynamicParameters();
  152. parameters.Add("@StationId", stationId, DbType.Int32, ParameterDirection.Input);
  153. 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; ";
  154. machineId = conn.ExecuteScalar<string>(strSql, parameters);
  155. }
  156. if (!string.IsNullOrEmpty(machineId))
  157. {
  158. decimal estimatedPwerValue = GetFCFSPower(stationId, machineId, setting.LBCurrent);
  159. // renew table
  160. UpdateLoadbalanceRecord(stationId, machineId, estimatedPwerValue, null, true);
  161. // UpdateLoadbalanceRecord(stationId, machineId, estimatedPwerValue, null);
  162. dic.Add(machineId, estimatedPwerValue);
  163. }
  164. }
  165. if (setting != null && setting.LBMode == 1)
  166. {
  167. dic = GetAveragePower(stationId, setting.LBCurrent);
  168. foreach (var kv in dic)
  169. {
  170. if (kv.Value.HasValue)
  171. {
  172. UpdateLoadbalanceRecord(stationId, kv.Key, 0, DateTime.UtcNow);
  173. UpdateLoadbalanceRecord(stationId, kv.Key, kv.Value.Value, null);
  174. }
  175. }
  176. }
  177. }
  178. return dic;
  179. }
  180. public Dictionary<string, decimal?> GetSettingPower(int stationId, string machineId)
  181. {
  182. Dictionary<string, decimal?> dic = new Dictionary<string, decimal?>();
  183. var setting = GetLoadBalance(stationId);
  184. if (setting == null) return null;
  185. lock (GetLock(stationId))
  186. {
  187. if (setting != null)
  188. {
  189. if (setting.LBMode == 1)
  190. {
  191. dic = GetAveragePower(stationId, setting.LBCurrent, machineId);
  192. foreach (var kv in dic)
  193. {
  194. if (kv.Value.HasValue)
  195. {
  196. UpdateLoadbalanceRecord(stationId, kv.Key, 0, DateTime.UtcNow);
  197. UpdateLoadbalanceRecord(stationId, kv.Key, kv.Value.Value, null);
  198. }
  199. }
  200. }
  201. else if (setting.LBMode == 2)
  202. {
  203. dic.Add(machineId, GetFCFSPower(stationId, machineId, setting.LBCurrent));
  204. UpdateLoadbalanceRecord(stationId, machineId, 0, DateTime.UtcNow);
  205. UpdateLoadbalanceRecord(stationId, machineId, dic[machineId].Value, null);
  206. }
  207. else
  208. {
  209. // 把LB TABLE 關閉
  210. CloseLoadbalanceRecord(stationId);
  211. }
  212. }
  213. }
  214. return dic;
  215. }
  216. public LoadBalanceSetting GetLoadBalance(int stationId)
  217. {
  218. LoadBalanceSetting setting = null;
  219. using (SqlConnection conn = new SqlConnection(webConnectionString))
  220. {
  221. var parameters = new DynamicParameters();
  222. parameters.Add("@StationId", stationId, DbType.Int32, ParameterDirection.Input);
  223. string strSql = "Select LBMode,LBCurrent from [dbo].[Station] where Id=@StationId ; ";
  224. setting = conn.Query<LoadBalanceSetting>(strSql, parameters).FirstOrDefault();
  225. }
  226. return setting;
  227. }
  228. private List<string> GetIdsbyStationId(int stationId)
  229. {
  230. List<string> machineIds = new List<string>();
  231. using (SqlConnection conn = new SqlConnection(webConnectionString))
  232. {
  233. var parameters = new DynamicParameters();
  234. parameters.Add("@StationId", stationId, DbType.Int16, ParameterDirection.Input);
  235. string strSql = "Select MachineId from [dbo].[StationMachine] where StationId=@StationId; ";
  236. machineIds = conn.Query<String>(strSql, parameters).ToList();
  237. }
  238. return machineIds;
  239. }
  240. private Dictionary<string, decimal?> GetAveragePower(int stationId, int availableCapacity, string machineId = "")
  241. {
  242. Dictionary<string, decimal?> dic = new Dictionary<string, decimal?>();
  243. //總量 * 該樁的額定功率/該站充電中樁的總額定功率
  244. List<string> _MachineIds = new List<string>();
  245. int skipCount = 0;
  246. int size = 200;
  247. int takeCount = 0;
  248. int totalRatePower = 0;
  249. using (SqlConnection conn = new SqlConnection(mainConnectionString))
  250. {
  251. var parameters = new DynamicParameters();
  252. parameters.Add("@StationId", stationId, DbType.Int32, ParameterDirection.Input);
  253. string strSql = "Select MachineId from [dbo].[LoadingBalance] where StationId=@StationId and FinishedOn='1991/01/01'; ";
  254. _MachineIds = conn.Query<string>(strSql, parameters).ToList();
  255. }
  256. if (!string.IsNullOrEmpty(machineId) && !_MachineIds.Contains(machineId))
  257. {
  258. _MachineIds.Add(machineId);
  259. }
  260. while (skipCount < _MachineIds.Count())
  261. {
  262. takeCount = _MachineIds.Count() - skipCount > size ? size : _MachineIds.Count() - skipCount;
  263. using (SqlConnection conn = new SqlConnection(mainConnectionString))
  264. {
  265. string strSql = "Select Sum(RatedPower) from [dbo].[Machine] where Id in @machineIds and [Online]=1; ";
  266. totalRatePower += conn.ExecuteScalar<Int32>(strSql, new { machineIds = _MachineIds.ToArray() });
  267. skipCount += takeCount;
  268. }
  269. }
  270. foreach (var id in _MachineIds)
  271. {
  272. int singleRatePower = (int)GetRatedPower(id);
  273. var value = totalRatePower == 0 ? 0 : availableCapacity * singleRatePower / totalRatePower;
  274. dic.Add(id, value);
  275. }
  276. return dic;
  277. }
  278. private decimal GetRatedPower(string machineId)
  279. {
  280. decimal ratedPower = 0;
  281. using (SqlConnection conn = new SqlConnection(mainConnectionString))
  282. {
  283. var parameters = new DynamicParameters();
  284. parameters.Add("@machineId", machineId, DbType.String, ParameterDirection.Input);
  285. string strSql = "Select RatedPower from [dbo].[Machine] where Id=@machineId; ";
  286. ratedPower = conn.ExecuteScalar<Int32>(strSql, parameters);
  287. }
  288. return ratedPower;
  289. }
  290. private decimal GetFCFSPower(int stationId, string machineId, int availableCapacity)
  291. {
  292. decimal ongoingPower = 0;
  293. decimal singleRatePower = GetRatedPower(machineId);
  294. //先找LB 裡面目前下發的Power
  295. decimal? currentPower = GetCurrentSetting(machineId);
  296. if (!currentPower.HasValue) currentPower = 0;
  297. //總量 - 所有正在進行的Power
  298. using (SqlConnection conn = new SqlConnection(mainConnectionString))
  299. {
  300. var parameters = new DynamicParameters();
  301. parameters.Add("@StationId", stationId, DbType.Int32, ParameterDirection.Input);
  302. string strSql = "Select Sum(Power) from [dbo].[LoadingBalance] where StationId=@StationId and FinishedOn='1991/01/01'; ";
  303. ongoingPower = conn.ExecuteScalar<Int32>(strSql, parameters);
  304. }
  305. return availableCapacity - (ongoingPower - currentPower.Value) > singleRatePower ? singleRatePower :
  306. (availableCapacity - (ongoingPower - currentPower.Value) > 0 ? availableCapacity - (ongoingPower - currentPower.Value) : 0);
  307. }
  308. }
  309. }