supply_air_temperature_set.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  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. cold_ratio = self.get_cold_ratio()
  71. temperature = self.calculate_by_cold_vav(cold_ratio)
  72. else:
  73. temperature = 25.0
  74. temperature = max(20.0, min(30.0, temperature))
  75. return temperature
  76. class ACATAHSupplyAirTemperatureDefaultController:
  77. """
  78. Determine supply air temperature when missing data.
  79. """
  80. def __init__(self, is_clear_day: bool):
  81. super(ACATAHSupplyAirTemperatureDefaultController, self).__init__()
  82. self.is_clear_day = is_clear_day
  83. def build(self) -> float:
  84. now = get_time_str()
  85. now_time_str = arrow.get(now, TIME_FMT).time().strftime('%H%M%S')
  86. if '080000' <= now_time_str < '100000':
  87. is_morning = True
  88. else:
  89. is_morning = False
  90. if is_morning:
  91. temperature = 27.0
  92. else:
  93. if self.is_clear_day:
  94. temperature = 23.0
  95. else:
  96. temperature = 25.0
  97. return temperature
  98. async def get_planned(project_id: str, device_id: str) -> float:
  99. vav_boxes_params = await fetch_status_params(project_id, device_id)
  100. vav_boxes_lit = vav_boxes_params['vav_boxes_list']
  101. async with AsyncClient() as client:
  102. platform = DataPlatformService(client, project_id)
  103. current_supply_air_temperature = await platform.get_realtime_supply_air_temperature(device_id)
  104. return_air_temperature = await platform.query_realtime_return_air_temperature(device_id)
  105. hot_water_valve_opening_set_duration = await platform.get_duration(
  106. InfoCode.hot_water_valve_opening_set, device_id, 15 * 60
  107. )
  108. chill_water_valve_opening_set_duration = await platform.get_duration(
  109. InfoCode.chill_water_valve_opening_set, device_id, 15 * 60
  110. )
  111. on_off_set_duration = await platform.get_duration(InfoCode.equip_switch_set, device_id, 20 * 60)
  112. # if hot_water_valve_opening_set_duration[-1]['value'] == 0.0:
  113. # thermal_mode = ThermalMode.cooling
  114. if chill_water_valve_opening_set_duration[-1]['value'] == 0.0:
  115. thermal_mode = ThermalMode.heating
  116. else:
  117. thermal_mode = ThermalMode.cooling
  118. is_off_to_on = False
  119. if on_off_set_duration[-1]['value'] == 1.0:
  120. for item in on_off_set_duration[::-1]:
  121. if item['value'] == 0.0:
  122. is_off_to_on = True
  123. break
  124. logger.debug(f'{device_id} was off to on: {is_off_to_on}')
  125. is_thermal_mode_switched = False
  126. if len(set([item['value'] for item in hot_water_valve_opening_set_duration])) > 1:
  127. is_thermal_mode_switched = True
  128. if len(set([item['value'] for item in chill_water_valve_opening_set_duration])) > 1:
  129. is_thermal_mode_switched = True
  130. controller = ACATAHSupplyAirTemperatureController(
  131. vav_boxes_lit,
  132. current_supply_air_temperature,
  133. return_air_temperature,
  134. thermal_mode,
  135. is_off_to_on,
  136. is_thermal_mode_switched
  137. )
  138. next_supply_air_temperature_set = controller.build()
  139. return next_supply_air_temperature_set
  140. async def get_default(project_id: str) -> float:
  141. async with AsyncClient() as client:
  142. weather_service = WeatherService(client)
  143. realtime_weather = await weather_service.get_realtime_weather(project_id)
  144. if realtime_weather.get('text') == '晴':
  145. is_clear_day = True
  146. else:
  147. is_clear_day = False
  148. controller = ACATAHSupplyAirTemperatureDefaultController(is_clear_day)
  149. next_supply_air_temperature_set = controller.build()
  150. return next_supply_air_temperature_set
  151. @logger.catch()
  152. async def get_next_supply_air_temperature_set(project_id: str, device_id: str) -> float:
  153. try:
  154. new = await get_planned(project_id, device_id)
  155. except KeyError and IndexError:
  156. new = await get_default(project_id)
  157. return new