Przeglądaj źródła

refactor equip control api

highing666 3 lat temu
rodzic
commit
a3b2388b38

+ 10 - 10
app/api/routers/devices.py

@@ -11,7 +11,8 @@ from app.controllers.equipment.fcu.on_ratio import start_on_ratio_mode
 from app.controllers.equipment.pau.freq_set import get_next_acatfu_freq_set
 from app.controllers.equipment.pau.supply_air_temperature_set import get_next_acatfu_supply_air_temperature_set
 from app.controllers.equipment.pau.switch import get_switch_action
-from app.controllers.equipment.vrf.basic import get_vrf_instructions
+from app.controllers.equipment.vav import build_acatva_instructions
+from app.controllers.equipment.vrf.basic import build_acatvi_instructions
 from app.models.domain.devices import DevicesInstructionsBaseResponse, DevicesEarlyStartTime
 
 router = APIRouter()
@@ -122,15 +123,12 @@ async def get_acatfc_early_start_time(
 
 
 @router.post('/instructions/acatvi', response_model=domain_devices.ACATVIInstructionsTemporaryResponse)
-async def get_acatvi_instructions(device_info: domain_devices.ACATVIInstructionsRequest):
-    output = await get_vrf_instructions(
-        device_info.space_temp_target,
-        device_info.return_air_temp,
-        device_info.space_realtime_temp
-    )
-    resp = {'output': output}
+async def get_acatvi_instructions(params: domain_devices.ACATVIInstructionsRequest):
+    instructions = await build_acatvi_instructions(params)
 
-    return resp
+    return {
+        'output': instructions
+    }
 
 
 @router.post('/instructions/acatfc', response_model=domain_devices.ACATFCInstructionsResponse)
@@ -142,4 +140,6 @@ async def get_acatfc_instructions(params: domain_devices.ACATFCInstructionsReque
 
 @router.post('/instructions/acatva', response_model=domain_devices.ACATVAInstructionsResponse)
 async def get_acatva_instructions(params: domain_devices.ACATVAInstructionsRequest):
-    pass
+    instructions = await build_acatva_instructions(params)
+
+    return instructions

+ 4 - 4
app/controllers/equipment/fcu/basic.py

@@ -98,12 +98,12 @@ class FCUControllerV2(EquipmentController):
         self.season = season
 
     def get_mode(self) -> int:
-        if not np.isnan(self.equipment.water_in_temperature):
+        if self.equipment.water_in_temperature > 0:
             if self.equipment.water_in_temperature > self.equipment.space.temperature_target:
                 mode = 2
             else:
                 mode = 1
-        elif not np.isnan(self.equipment.supply_air_temperature):
+        elif self.equipment.supply_air_temperature > 0:
             if self.equipment.supply_air_temperature > self.equipment.space.temperature_target:
                 mode = 2
             else:
@@ -227,8 +227,8 @@ async def build_acatfc_instructions(params: ACATFCInstructionsRequest) -> Dict:
     )
     fcu = FCU(
         space=space,
-        supply_air_temperature=params.supply_air_temperature,
-        water_in_temperature=params.water_in_temperature
+        supply_air_temperature=-1.0,
+        water_in_temperature=-1.0
     )
 
     controller = FCUControllerV2(fcu, Season(params.season))

+ 73 - 2
app/controllers/equipment/vav.py

@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 
 from operator import attrgetter
-from typing import Dict, List, Tuple
+from typing import Dict, List, Optional, Tuple
 
 import numpy as np
 from fastapi import HTTPException
@@ -11,6 +11,7 @@ from sqlalchemy.orm import Session
 
 from app.controllers.equipment.controller import EquipmentController
 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.sapce_weight import SpaceWeight
 from app.schemas.space import Space
@@ -89,7 +90,7 @@ class VAVController(EquipmentController):
 
 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)
         self.weights = weights
         self.season = season
@@ -174,6 +175,53 @@ class VAVControllerV2(VAVController):
         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 with AsyncClient() as client:
         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()
 
     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

+ 10 - 9
app/controllers/equipment/vrf/basic.py

@@ -4,6 +4,7 @@ import numpy as np
 from loguru import logger
 
 from app.controllers.equipment.controller import EquipmentController
+from app.models.domain.devices import ACATVIInstructionsRequest
 from app.schemas.equipment import VRF
 
 
@@ -75,10 +76,10 @@ class VRFController(EquipmentController):
 
 
 @logger.catch()
-async def get_vrf_instructions(target: float, return_air_temp: float, realtime: float) -> Dict:
-    target = np.NAN if target == -1.0 else target
-    realtime = np.NAN if realtime == -1.0 else realtime
-    return_air_temp = np.NAN if realtime == -1.0 else return_air_temp
+async def build_acatvi_instructions(params: ACATVIInstructionsRequest) -> Dict:
+    target = np.NAN if params.space_temperature_target == -1.0 else params.space_temperature_target
+    realtime = np.NAN if params.space_realtime_temperature == -1.0 else params.space_realtime_temperature
+    return_air_temp = np.NAN if params.return_air_temperature == -1.0 else params.return_air_temperature
 
     vrf = VRF(return_air_temp=return_air_temp)
 
@@ -86,10 +87,10 @@ async def get_vrf_instructions(target: float, return_air_temp: float, realtime:
     await controller.run()
     regulated_vrf = controller.get_results()
 
-    output = {'switch_set': 'on' if regulated_vrf.equip_switch_set else 'off'}
+    instructions = {'switch_set': 'on' if regulated_vrf.equip_switch_set else 'off'}
     if regulated_vrf.equip_switch_set:
-        output.update({'speed_set': regulated_vrf.speed_set})
-        output.update({'temperature_set': regulated_vrf.temperature_set})
-        output.update({'mode_set': regulated_vrf.mode_set})
+        instructions.update({'speed_set': regulated_vrf.speed_set})
+        instructions.update({'temperature_set': regulated_vrf.temperature_set})
+        instructions.update({'mode_set': regulated_vrf.mode_set})
 
-    return output
+    return instructions

+ 4 - 6
app/models/domain/devices.py

@@ -23,9 +23,9 @@ class DevicesEarlyStartTime(BaseModel):
 
 
 class ACATVIInstructionsRequest(BaseModel):
-    return_air_temp: float
-    space_temp_target: float
-    space_realtime_temp: float
+    return_air_temperature: float
+    space_temperature_target: float
+    space_realtime_temperature: float
 
 
 class ACATVIInstructionsTemporaryResponse(BaseModel):
@@ -41,8 +41,6 @@ class ACATVIInstructionsResponse(BaseModel):
 
 class ACATFCInstructionsRequest(BaseModel):
     season: str
-    supply_air_temperature: Optional[float]
-    water_in_temperature: Optional[float]
     space_temperature_target: float
     space_realtime_temperature: Optional[float]
 
@@ -74,5 +72,5 @@ class ACATVAInstructionsRequest(BaseModel):
 
 class ACATVAInstructionsResponse(BaseModel):
     supply_air_flow_set: float
-    virtual_target_temperature_set: float
+    virtual_temperature_target_set: float
     virtual_realtime_temperature: float

+ 5 - 1
app/schemas/space.py

@@ -6,9 +6,13 @@ from pydantic import BaseModel
 
 
 class Space(BaseModel):
-    id: str
+    id: Optional[str]
     realtime_temperature: float
     equipment: Optional[List]
     temperature_target: Optional[float]
     comfortable_temperature: Optional[float]
     diff: Optional[float]
+    vav_default_weight: Optional[float]
+    vav_temporary_weight: Optional[float]
+    vav_temporary_update_time: Optional[str]
+