basic.py 7.8 KB

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