|
@@ -1,7 +1,7 @@
|
|
# -*- coding: utf-8 -*-
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
from operator import attrgetter
|
|
from operator import attrgetter
|
|
-from typing import Dict, List, Tuple
|
|
|
|
|
|
+from typing import Dict, List, Optional, Tuple
|
|
|
|
|
|
import numpy as np
|
|
import numpy as np
|
|
from fastapi import HTTPException
|
|
from fastapi import HTTPException
|
|
@@ -11,6 +11,7 @@ from sqlalchemy.orm import Session
|
|
|
|
|
|
from app.controllers.equipment.controller import EquipmentController
|
|
from app.controllers.equipment.controller import EquipmentController
|
|
from app.crud.space.weight import get_weights_by_vav
|
|
from app.crud.space.weight import get_weights_by_vav
|
|
|
|
+from app.models.domain.devices import ACATVAInstructionsRequest
|
|
from app.schemas.equipment import VAVBox, FCU
|
|
from app.schemas.equipment import VAVBox, FCU
|
|
from app.schemas.sapce_weight import SpaceWeight
|
|
from app.schemas.sapce_weight import SpaceWeight
|
|
from app.schemas.space import Space
|
|
from app.schemas.space import Space
|
|
@@ -89,7 +90,7 @@ class VAVController(EquipmentController):
|
|
|
|
|
|
class VAVControllerV2(VAVController):
|
|
class VAVControllerV2(VAVController):
|
|
|
|
|
|
- def __init__(self, equipment: VAVBox, weights: List[SpaceWeight], season: Season):
|
|
|
|
|
|
+ def __init__(self, equipment: VAVBox, weights: Optional[List[SpaceWeight]] = None, season: Optional[Season] = None):
|
|
super(VAVControllerV2, self).__init__(equipment)
|
|
super(VAVControllerV2, self).__init__(equipment)
|
|
self.weights = weights
|
|
self.weights = weights
|
|
self.season = season
|
|
self.season = season
|
|
@@ -174,6 +175,53 @@ class VAVControllerV2(VAVController):
|
|
self.equipment.running_status = True
|
|
self.equipment.running_status = True
|
|
|
|
|
|
|
|
|
|
|
|
+class VAVControllerV3(VAVControllerV2):
|
|
|
|
+
|
|
|
|
+ def __init__(self, vav_params: VAVBox, season: Season):
|
|
|
|
+ super(VAVControllerV3, self).__init__(vav_params)
|
|
|
|
+ self.season = season
|
|
|
|
+
|
|
|
|
+ def get_valid_spaces(self) -> List:
|
|
|
|
+ valid_spaces = list()
|
|
|
|
+ for sp in self.equipment.spaces:
|
|
|
|
+ if sp.realtime_temperature > 0.0 and sp.temperature_target > 22.0:
|
|
|
|
+ valid_spaces.append(sp)
|
|
|
|
+
|
|
|
|
+ return valid_spaces
|
|
|
|
+
|
|
|
|
+ async def build_virtual_temperature(self) -> None:
|
|
|
|
+ valid_spaces = self.get_valid_spaces()
|
|
|
|
+
|
|
|
|
+ if not valid_spaces:
|
|
|
|
+ virtual_realtime, virtual_target = np.NAN, np.NAN
|
|
|
|
+ else:
|
|
|
|
+ sorted_spaces = sorted(valid_spaces, key=lambda x: x.vav_temporary_update_time)
|
|
|
|
+ if sorted_spaces[-1].vav_temporary_update_time > get_time_str(60 * 60 * 2, flag='ago'):
|
|
|
|
+ virtual_realtime = sorted_spaces[-1].realtime_temperature
|
|
|
|
+ virtual_target = sorted_spaces[-1].temperature_target
|
|
|
|
+ else:
|
|
|
|
+ virtual_realtime, virtual_target = 0.0, 0.0
|
|
|
|
+ total_weight = 0.0
|
|
|
|
+ for sp in valid_spaces:
|
|
|
|
+ temp_weight = sp.vav_default_weight
|
|
|
|
+ virtual_realtime += sp.realtime_temperature * temp_weight
|
|
|
|
+ virtual_target += sp.temperature_target * temp_weight
|
|
|
|
+ total_weight += temp_weight
|
|
|
|
+
|
|
|
|
+ if total_weight == 0:
|
|
|
|
+ for sp in valid_spaces:
|
|
|
|
+ virtual_realtime += sp.realtime_temperature
|
|
|
|
+ virtual_target += sp.temperature_target
|
|
|
|
+ virtual_realtime /= len(valid_spaces)
|
|
|
|
+ virtual_target /= len(valid_spaces)
|
|
|
|
+ else:
|
|
|
|
+ virtual_realtime /= total_weight
|
|
|
|
+ virtual_target /= total_weight
|
|
|
|
+
|
|
|
|
+ self.equipment.virtual_realtime_temperature = virtual_realtime
|
|
|
|
+ self.equipment.virtual_target_temperature = virtual_target
|
|
|
|
+
|
|
|
|
+
|
|
async def fetch_vav_control_params(project_id: str, equipment_id: str) -> Dict:
|
|
async def fetch_vav_control_params(project_id: str, equipment_id: str) -> Dict:
|
|
async with AsyncClient() as client:
|
|
async with AsyncClient() as client:
|
|
duo_duo = Duoduo(client, project_id)
|
|
duo_duo = Duoduo(client, project_id)
|
|
@@ -251,3 +299,26 @@ async def get_vav_control_v2(db: Session, project_id: str, equipment_id: str) ->
|
|
regulated_vav = vav_controller.get_results()
|
|
regulated_vav = vav_controller.get_results()
|
|
|
|
|
|
return regulated_vav
|
|
return regulated_vav
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+@logger.catch()
|
|
|
|
+async def build_acatva_instructions(params: ACATVAInstructionsRequest) -> Dict:
|
|
|
|
+ vav_params = VAVBox(
|
|
|
|
+ spaces=params.spaces,
|
|
|
|
+ supply_air_temperature=params.supply_air_temperature,
|
|
|
|
+ supply_air_flow=params.supply_air_flow,
|
|
|
|
+ supply_air_flow_lower_limit=params.supply_air_flow_lower_limit,
|
|
|
|
+ supply_air_flow_upper_limit=params.supply_air_flow_upper_limit
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ controller = VAVControllerV3(vav_params=vav_params, season=Season(params.season))
|
|
|
|
+ await controller.run()
|
|
|
|
+ regulated_vav = controller.get_results()
|
|
|
|
+
|
|
|
|
+ instructions = {
|
|
|
|
+ 'supply_air_flow_set': regulated_vav.supply_air_flow_set,
|
|
|
|
+ 'virtual_temperature_target_set': regulated_vav.virtual_target_temperature,
|
|
|
|
+ 'virtual_realtime_temperature': regulated_vav.virtual_realtime_temperature
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return instructions
|