thermal_mode.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. from typing import Dict, List
  2. from httpx import AsyncClient
  3. from loguru import logger
  4. from app.models.domain.devices import ThermalMode
  5. from app.models.domain.devices import ACATAHThermalModeSetRequest
  6. from app.schemas.equipment import VAVBox
  7. from app.services.platform import DataPlatformService, InfoCode
  8. from app.services.transfer import Duoduo, Season
  9. def count_vav_box_weight(
  10. realtime: float,
  11. target: float,
  12. upper_limit_flow: float,
  13. lower_limit_flow: float,
  14. current_flow_set: float,
  15. valve_opening: float,
  16. season: Season,
  17. ) -> float:
  18. diff = realtime - target
  19. flag = False
  20. if current_flow_set < lower_limit_flow * 1.1:
  21. if season == Season.cooling:
  22. if diff < 0:
  23. flag = True
  24. if season == Season.heating:
  25. if diff > 0:
  26. flag = True
  27. elif current_flow_set > upper_limit_flow * 0.9:
  28. if valve_opening > 90.0:
  29. if season == Season.cooling:
  30. if diff > 0:
  31. flag = True
  32. if season == Season.heating:
  33. if diff < 0:
  34. flag = True
  35. if flag:
  36. if abs(diff) < 1:
  37. weight = 0.0
  38. else:
  39. weight = diff
  40. weight = max(-4.0, min(4.0, weight))
  41. else:
  42. weight = 0
  43. return weight
  44. class ACATAHThermalModeController:
  45. """
  46. Decide whether to use cooling or heating mode according to space condition
  47. controlled by VAV Box.
  48. Writen by WuXu
  49. """
  50. def __init__(self, vav_boxes_list: List[VAVBox], season: Season):
  51. super(ACATAHThermalModeController, self).__init__()
  52. self.vav_boxes_list = vav_boxes_list
  53. self.season = season
  54. def build(self) -> str:
  55. weight = 0.0
  56. for box in self.vav_boxes_list:
  57. weight += count_vav_box_weight(
  58. box.virtual_realtime_temperature,
  59. box.virtual_target_temperature,
  60. box.supply_air_flow_upper_limit,
  61. box.supply_air_flow_lower_limit,
  62. box.supply_air_flow_set,
  63. box.valve_opening,
  64. self.season,
  65. )
  66. if weight > 0:
  67. mode = "cooling"
  68. elif weight < 0:
  69. mode = "heating"
  70. else:
  71. mode = "hold"
  72. return mode
  73. async def fetch_status_params(project_id: str, device_id: str) -> Dict:
  74. async with AsyncClient() as client:
  75. platform = DataPlatformService(client, project_id)
  76. duoduo = Duoduo(client, project_id)
  77. season = duoduo.get_season()
  78. relations = await platform.query_relations(
  79. from_id=device_id, graph_id="GtControlEquipNetwork001"
  80. )
  81. vav_id_list = [item.get("to_id") for item in relations]
  82. vav_boxes_list = []
  83. for vav_id in vav_id_list:
  84. virtual_realtime_temperature = await duoduo.query_device_virtual_data(
  85. vav_id, "VirtualRealtimeTemperature"
  86. )
  87. virtual_temperature_target = await duoduo.query_device_virtual_data(
  88. vav_id, "TargetTemperatureSet"
  89. )
  90. lower_limit_flow, upper_limit_flow = await platform.get_air_flow_limit(
  91. vav_id
  92. )
  93. current_flow_set = await platform.get_realtime_data(
  94. InfoCode.supply_air_flow_set, vav_id
  95. )
  96. valve_opening = await platform.get_realtime_data(
  97. InfoCode.valve_opening, vav_id
  98. )
  99. vav_params = {
  100. "id": vav_id,
  101. "virtual_realtime_temperature": virtual_realtime_temperature,
  102. "virtual_target_temperature": virtual_temperature_target,
  103. "supply_air_flow_lower_limit": lower_limit_flow,
  104. "supply_air_flow_upper_limit": upper_limit_flow,
  105. "supply_air_flow_set": current_flow_set,
  106. "valve_opening": valve_opening,
  107. }
  108. vav = VAVBox(**vav_params)
  109. vav_boxes_list.append(vav)
  110. return {"vav_boxes_list": vav_boxes_list, "season": season}
  111. @logger.catch()
  112. async def get_thermal_mode(project_id: str, device_id: str) -> ThermalMode:
  113. prams = await fetch_status_params(project_id, device_id)
  114. controller = ACATAHThermalModeController(
  115. prams.get("vav_boxes_list"), prams.get("season")
  116. )
  117. mode = controller.build()
  118. return ThermalMode(mode)
  119. @logger.catch()
  120. def build_acatah_thermal_mode_set(params: ACATAHThermalModeSetRequest) -> str:
  121. vav_list = list()
  122. for raw_vav in params.vav_list:
  123. vav = VAVBox(
  124. virtual_realtime_temperature=raw_vav.virtual_realtime_temperature,
  125. virtual_target_temperature=raw_vav.virtual_temperature_target,
  126. supply_air_flow_lower_limit=raw_vav.supply_air_flow_lower_limit,
  127. supply_air_flow_upper_limit=raw_vav.supply_air_flow_upper_limit,
  128. supply_air_flow_set=raw_vav.supply_air_flow_set,
  129. valve_opening=raw_vav.valve_opening,
  130. )
  131. vav_list.append(vav)
  132. controller = ACATAHThermalModeController(vav_list, Season(params.season))
  133. mode = controller.build()
  134. return mode