basic.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. # -*- coding: utf-8 -*-
  2. from typing import Dict, List, Tuple
  3. import arrow
  4. import numpy as np
  5. from app.api.errors.iot import MissingIOTDataError
  6. from app.models.domain.devices import ASHPRequest
  7. from app.schemas.equipment import ASHP
  8. from app.schemas.season import Season
  9. class ASHPGroupController:
  10. def __init__(self, ashp_list: List[ASHP], outdoor_temp_list: List[float], season: Season):
  11. self._season = season
  12. self._ashp_list = ashp_list
  13. self._outdoor_temp_list = outdoor_temp_list
  14. self._interval = 0
  15. self._is_warning = False
  16. def initialization(self) -> Tuple[float, float]:
  17. if self._season == Season.cooling:
  18. if self._outdoor_temp_list:
  19. outdoor_temp_avg = np.mean(self._outdoor_temp_list)
  20. else:
  21. outdoor_temp_avg = 22.0
  22. total_device_num = len(self._ashp_list)
  23. if outdoor_temp_avg <= 20.0:
  24. device_num = 1
  25. out_temp_set = 10.0
  26. interval = 45 * 60
  27. elif outdoor_temp_avg < 24.0:
  28. device_num = total_device_num // 3
  29. out_temp_set = 9.0
  30. interval = 0
  31. else:
  32. device_num = total_device_num // 3 + 1
  33. out_temp_set = 8.5
  34. interval = 0
  35. if self._outdoor_temp_list:
  36. if np.max(self._outdoor_temp_list) > 34.0:
  37. device_num += 1
  38. device_num = min(device_num, total_device_num - 1)
  39. elif self._season == Season.heating:
  40. if self._outdoor_temp_list:
  41. outdoor_temp_avg = np.mean(self._outdoor_temp_list)
  42. else:
  43. outdoor_temp_avg = -10.0
  44. total_device_num = len(self._ashp_list)
  45. if outdoor_temp_avg >= 0.0:
  46. device_num = 1
  47. out_temp_set = 45.0
  48. interval = 45 * 60
  49. elif outdoor_temp_avg > -15.0:
  50. device_num = total_device_num // 3
  51. out_temp_set = 45.0
  52. interval = 0
  53. else:
  54. device_num = total_device_num // 3 + 1
  55. out_temp_set = 50.0
  56. interval = 0
  57. if self._outdoor_temp_list:
  58. if np.min(self._outdoor_temp_list) < -15.0:
  59. device_num += 1
  60. device_num = min(device_num, total_device_num - 1)
  61. else:
  62. device_num = 0
  63. interval = 0
  64. out_temp_set = np.NAN
  65. self._interval = interval
  66. return device_num, out_temp_set
  67. def device_num_adjustment(self) -> Tuple[float, float]:
  68. out_temp_15_avg = np.mean(
  69. [np.mean(device.out_temp_15min) for device in self._ashp_list if device.running_status])
  70. out_temp_set_15_avg = np.mean(
  71. [np.mean(device.out_temp_set_15min) for device in self._ashp_list if device.running_status])
  72. iplr_15_avg = np.mean([np.mean(device.iplr_15min) for device in self._ashp_list if device.running_status])
  73. out_temp_30_avg = np.mean(
  74. [np.mean(device.out_temp_30min) for device in self._ashp_list if device.running_status])
  75. out_temp_set_30_avg = np.mean(
  76. [np.mean(device.out_temp_set_30min) for device in self._ashp_list if device.running_status])
  77. iplr_30_avg = np.mean([np.mean(device.iplr_30min) for device in self._ashp_list if device.running_status])
  78. device_num_diff = 0
  79. if self._season == Season.cooling:
  80. if out_temp_15_avg < out_temp_set_15_avg - 1 and iplr_15_avg > 0.85:
  81. device_num_diff = 1
  82. if out_temp_30_avg > out_temp_set_30_avg + 1 and iplr_30_avg <= 0.85:
  83. device_num_diff = 1
  84. self._is_warning = True
  85. if out_temp_15_avg >= out_temp_set_15_avg and iplr_15_avg < 0.6:
  86. device_num_diff = -1
  87. elif self._season == Season.heating:
  88. if out_temp_15_avg > out_temp_set_15_avg + 1 and iplr_15_avg > 0.85:
  89. device_num_diff = 1
  90. if out_temp_30_avg > out_temp_set_30_avg + 1 and iplr_30_avg <= 0.85:
  91. device_num_diff = 1
  92. self._is_warning = True
  93. if out_temp_15_avg <= out_temp_set_15_avg + 0.3 and iplr_15_avg < 0.6:
  94. device_num_diff = -1
  95. return device_num_diff, float(out_temp_set_30_avg)
  96. def out_temp_set_adjustment(self) -> float:
  97. out_temp_set = np.NAN
  98. if self._outdoor_temp_list:
  99. current_outdoor_temp = self._outdoor_temp_list[-1]
  100. if self._season == Season.cooling:
  101. if current_outdoor_temp >= 30.0:
  102. out_temp_set = 8.0
  103. elif current_outdoor_temp >= 28.0:
  104. out_temp_set = 8.5
  105. elif current_outdoor_temp >= 26.0:
  106. out_temp_set = 9.0
  107. elif current_outdoor_temp > 22.0:
  108. out_temp_set = 10.0
  109. else:
  110. out_temp_set = 11.0
  111. elif self._season == Season.heating:
  112. if current_outdoor_temp > 10.0:
  113. out_temp_set = 40.0
  114. elif current_outdoor_temp >= 0.0:
  115. out_temp_set = 45.0
  116. elif current_outdoor_temp > -10.0:
  117. out_temp_set = 50.0
  118. else:
  119. out_temp_set = 55.0
  120. return out_temp_set
  121. def build_up(self, diff: float, out_temp_set: float):
  122. if diff > 0:
  123. for device in self._ashp_list:
  124. if not device.running_status:
  125. device.equip_switch_set = True
  126. diff -= 1
  127. if diff == 0:
  128. break
  129. elif diff < 0:
  130. for device in self._ashp_list:
  131. if device.running_status:
  132. device.equip_switch_set = False
  133. diff += 1
  134. if diff == 0:
  135. break
  136. if not np.isnan(out_temp_set):
  137. for device in self._ashp_list:
  138. if device.equip_switch_set:
  139. device.out_temp_set = out_temp_set
  140. def turn_off_all(self):
  141. for device in self._ashp_list:
  142. device.equip_switch_set = False
  143. def antifreeze(self):
  144. pass
  145. def run(self):
  146. t = arrow.utcnow()
  147. on_time = arrow.get(self._ashp_list[0].on_time, 'HHmmss')
  148. off_time = arrow.get(self._ashp_list[0].off_time, 'HHmmss')
  149. if off_time.hour > on_time.hour:
  150. if not on_time.hour < t.hour < off_time.hour:
  151. self.turn_off_all()
  152. return
  153. else:
  154. if off_time.hour < t.hour < on_time.hour:
  155. self.turn_off_all()
  156. return
  157. if t.minute < 30:
  158. if t.hour == 1:
  159. if not np.any([device.running_status for device in self._ashp_list]): # no device is running
  160. device_num_diff, out_temp_set = self.initialization()
  161. self.build_up(device_num_diff, out_temp_set)
  162. else:
  163. device_num_diff, out_temp_set = self.device_num_adjustment()
  164. self.build_up(device_num_diff, out_temp_set)
  165. else:
  166. out_temp_set = self.out_temp_set_adjustment()
  167. self.build_up(0, out_temp_set)
  168. def get_results(self) -> Tuple[List[ASHP], float, bool]:
  169. return self._ashp_list, self._interval, self._is_warning
  170. async def build_ashp_instructions(params: ASHPRequest) -> Dict:
  171. controller = ASHPGroupController(params.device_list, params.outdoor_temp, params.season)
  172. try:
  173. controller.run()
  174. except (TypeError, IndexError):
  175. raise MissingIOTDataError
  176. device_list, interval, is_warning = controller.get_results()
  177. instructions = {
  178. "device_list": device_list,
  179. "interval": interval,
  180. "is_warning": is_warning
  181. }
  182. return instructions