supply_air_temperature_set.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. from typing import List
  2. import arrow
  3. from httpx import AsyncClient
  4. from loguru import logger
  5. from app.controllers.equipment.ahu.thermal_mode import count_vav_box_weight, fetch_status_params
  6. from app.models.domain.devices import ThermalMode
  7. from app.schemas.equipment import VAVBox
  8. from app.services.platform import DataPlatformService, InfoCode
  9. from app.services.weather import WeatherService
  10. from app.utils.date import get_time_str, TIME_FMT
  11. class ACATAHSupplyAirTemperatureController:
  12. """
  13. Supply air temperature setting logic version 2 by WuXu.
  14. """
  15. def __init__(
  16. self,
  17. vav_boxes_list: List[VAVBox],
  18. current: float,
  19. return_air: float,
  20. thermal_mode: ThermalMode,
  21. is_off_to_on: bool,
  22. is_thermal_mode_switched: bool
  23. ):
  24. super(ACATAHSupplyAirTemperatureController, self).__init__()
  25. self.vav_boxes_list = vav_boxes_list
  26. self.current = current
  27. self.return_air = return_air
  28. self.thermal_mode = thermal_mode
  29. self.is_off_to_on = is_off_to_on
  30. self.is_thermal_mode_switched = is_thermal_mode_switched
  31. def calculate_by_cold_vav(self, cold_ratio: float) -> float:
  32. if self.thermal_mode == ThermalMode.cooling:
  33. if cold_ratio < 0.3:
  34. new = self.current - 1.0
  35. elif cold_ratio < 0.45:
  36. new = self.current - 0.5
  37. elif cold_ratio <= 0.55:
  38. new = self.current
  39. elif cold_ratio <= 0.7:
  40. new = self.current + 1.0
  41. elif cold_ratio <= 1.0:
  42. new = self.return_air
  43. else:
  44. new = self.current
  45. elif self.thermal_mode == ThermalMode.heating:
  46. if cold_ratio < 0.3:
  47. new = self.return_air
  48. elif cold_ratio < 0.45:
  49. new = self.current - 1
  50. elif cold_ratio <= 0.55:
  51. new = self.current
  52. elif cold_ratio <= 0.7:
  53. new = self.current + 0.5
  54. elif cold_ratio <= 1.0:
  55. new = self.current + 1
  56. else:
  57. new = self.current
  58. else:
  59. new = self.current
  60. return new
  61. def get_cold_ratio(self):
  62. cold, total = 0, 0
  63. for box in self.vav_boxes_list:
  64. temp = count_vav_box_weight(box.virtual_realtime_temperature, box.virtual_target_temperature)
  65. cold += temp if temp < 0 else 0
  66. total += abs(temp)
  67. return abs(cold / total)
  68. def build(self) -> float:
  69. if not self.is_off_to_on:
  70. if self.is_thermal_mode_switched:
  71. if self.thermal_mode == ThermalMode.heating:
  72. temperature = self.return_air + 1
  73. else:
  74. temperature = self.return_air - 1
  75. else:
  76. cold_ratio = self.get_cold_ratio()
  77. temperature = self.calculate_by_cold_vav(cold_ratio)
  78. else:
  79. temperature = 30.0
  80. temperature = max(20.0, min(30.0, temperature))
  81. return temperature
  82. class ACATAHSupplyAirTemperatureDefaultController:
  83. """
  84. Determine supply air temperature when missing data.
  85. """
  86. def __init__(self, is_clear_day: bool):
  87. super(ACATAHSupplyAirTemperatureDefaultController, self).__init__()
  88. self.is_clear_day = is_clear_day
  89. def build(self) -> float:
  90. now = get_time_str()
  91. now_time_str = arrow.get(now, TIME_FMT).time().strftime('%H%M%S')
  92. if '080000' <= now_time_str < '100000':
  93. is_morning = True
  94. else:
  95. is_morning = False
  96. if is_morning:
  97. temperature = 27.0
  98. else:
  99. if self.is_clear_day:
  100. temperature = 23.0
  101. else:
  102. temperature = 25.0
  103. return temperature
  104. async def get_planned(project_id: str, device_id: str) -> float:
  105. vav_boxes_params = await fetch_status_params(project_id, device_id)
  106. vav_boxes_lit = vav_boxes_params['vav_boxes_list']
  107. async with AsyncClient() as client:
  108. platform = DataPlatformService(client, project_id)
  109. current_supply_air_temperature = await platform.get_realtime_supply_air_temperature(device_id)
  110. return_air_temperature = await platform.query_realtime_return_air_temperature(device_id)
  111. hot_water_valve_opening_set_duration = await platform.get_duration(
  112. InfoCode.hot_water_valve_opening_set, device_id, 15 * 60
  113. )
  114. chill_water_valve_opening_set_duration = await platform.get_duration(
  115. InfoCode.chill_water_valve_opening_set, device_id, 15 * 60
  116. )
  117. on_off_set_duration = await platform.get_duration(InfoCode.equip_switch_set, device_id, 15 * 60)
  118. # if hot_water_valve_opening_set_duration[-1]['value'] == 0.0:
  119. # thermal_mode = ThermalMode.cooling
  120. if chill_water_valve_opening_set_duration[-1]['value'] == 0.0:
  121. thermal_mode = ThermalMode.heating
  122. else:
  123. thermal_mode = ThermalMode.cooling
  124. is_off_to_on = False
  125. if on_off_set_duration[-1]['value'] == 1.0:
  126. for item in on_off_set_duration[::-1]:
  127. if item['value'] == 0.0:
  128. is_off_to_on = True
  129. break
  130. is_thermal_mode_switched = False
  131. if len(set([item['value'] for item in hot_water_valve_opening_set_duration])) > 1:
  132. is_thermal_mode_switched = True
  133. if len(set([item['value'] for item in chill_water_valve_opening_set_duration])) > 1:
  134. is_thermal_mode_switched = True
  135. controller = ACATAHSupplyAirTemperatureController(
  136. vav_boxes_lit,
  137. current_supply_air_temperature,
  138. return_air_temperature,
  139. thermal_mode,
  140. is_off_to_on,
  141. is_thermal_mode_switched
  142. )
  143. next_supply_air_temperature_set = controller.build()
  144. return next_supply_air_temperature_set
  145. async def get_default(project_id: str) -> float:
  146. async with AsyncClient() as client:
  147. weather_service = WeatherService(client)
  148. realtime_weather = await weather_service.get_realtime_weather(project_id)
  149. if realtime_weather.get('text') == '晴':
  150. is_clear_day = True
  151. else:
  152. is_clear_day = False
  153. controller = ACATAHSupplyAirTemperatureDefaultController(is_clear_day)
  154. next_supply_air_temperature_set = controller.build()
  155. return next_supply_air_temperature_set
  156. @logger.catch()
  157. async def get_next_supply_air_temperature_set(project_id: str, device_id: str) -> float:
  158. try:
  159. new = await get_planned(project_id, device_id)
  160. except KeyError and IndexError:
  161. new = await get_default(project_id)
  162. return new