|
@@ -1,6 +1,6 @@
|
|
# -*- coding: utf-8 -*-
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
-from typing import List, Tuple
|
|
|
|
|
|
+from typing import Dict, List, Tuple
|
|
|
|
|
|
import numpy as np
|
|
import numpy as np
|
|
from fastapi import HTTPException
|
|
from fastapi import HTTPException
|
|
@@ -20,15 +20,13 @@ from app.utils.date import get_time_str
|
|
|
|
|
|
class VAVController(EquipmentController):
|
|
class VAVController(EquipmentController):
|
|
|
|
|
|
- def __init__(self, equipment: VAVBox, weights: List[SpaceWeight], season: Season):
|
|
|
|
|
|
+ def __init__(self, equipment: VAVBox):
|
|
super(VAVController, self).__init__()
|
|
super(VAVController, self).__init__()
|
|
- self._equipment = equipment
|
|
|
|
- self.weights = weights
|
|
|
|
- self.season = season
|
|
|
|
|
|
+ self.equipment = equipment
|
|
|
|
|
|
async def get_strategy(self):
|
|
async def get_strategy(self):
|
|
strategy = 'Plan A'
|
|
strategy = 'Plan A'
|
|
- for space in self._equipment.spaces:
|
|
|
|
|
|
+ for space in self.equipment.spaces:
|
|
for eq in space.equipment:
|
|
for eq in space.equipment:
|
|
if isinstance(eq, FCU):
|
|
if isinstance(eq, FCU):
|
|
strategy = 'Plan B'
|
|
strategy = 'Plan B'
|
|
@@ -36,11 +34,11 @@ class VAVController(EquipmentController):
|
|
|
|
|
|
return strategy
|
|
return strategy
|
|
|
|
|
|
- async def build_virtual_temperature_v1(self) -> Tuple[float, float]:
|
|
|
|
|
|
+ async def build_virtual_temperature(self) -> Tuple[float, float]:
|
|
target_list, realtime_list = [], []
|
|
target_list, realtime_list = [], []
|
|
buffer_list = []
|
|
buffer_list = []
|
|
strategy = await self.get_strategy()
|
|
strategy = await self.get_strategy()
|
|
- for space in self._equipment.spaces:
|
|
|
|
|
|
+ for space in self.equipment.spaces:
|
|
if not np.isnan(space.temperature_target):
|
|
if not np.isnan(space.temperature_target):
|
|
target_list.append(space.temperature_target)
|
|
target_list.append(space.temperature_target)
|
|
realtime_list.append(space.realtime_temperature)
|
|
realtime_list.append(space.realtime_temperature)
|
|
@@ -58,16 +56,50 @@ class VAVController(EquipmentController):
|
|
if total_target and total_realtime:
|
|
if total_target and total_realtime:
|
|
target_result = np.array(total_target).sum() / len(target_list)
|
|
target_result = np.array(total_target).sum() / len(target_list)
|
|
realtime_result = np.array(total_realtime).sum() / len(realtime_list)
|
|
realtime_result = np.array(total_realtime).sum() / len(realtime_list)
|
|
- self._equipment.setting_temperature = target_result
|
|
|
|
|
|
+ self.equipment.setting_temperature = target_result
|
|
else:
|
|
else:
|
|
target_result, realtime_result = np.NAN, np.NAN
|
|
target_result, realtime_result = np.NAN, np.NAN
|
|
|
|
|
|
return target_result, realtime_result
|
|
return target_result, realtime_result
|
|
|
|
|
|
- async def build_virtual_temperature_v2(self):
|
|
|
|
|
|
+ async def get_supply_air_flow_set(self, temperature_set: float, temperature_realtime: float) -> float:
|
|
|
|
+ if np.isnan(temperature_set) or np.isnan(temperature_realtime):
|
|
|
|
+ supply_air_flow_set = 0.0
|
|
|
|
+ else:
|
|
|
|
+ temperature_supply = self.equipment.supply_air_temperature
|
|
|
|
+ if np.isnan(temperature_supply):
|
|
|
|
+ temperature_supply = 19.0
|
|
|
|
+ supply_air_flow_set = self.equipment.supply_air_flow * ((temperature_supply - temperature_realtime)
|
|
|
|
+ / (temperature_supply - temperature_set))
|
|
|
|
+ supply_air_flow_set = max(self.equipment.supply_air_flow_lower_limit, supply_air_flow_set)
|
|
|
|
+ supply_air_flow_set = min(self.equipment.supply_air_flow_upper_limit, supply_air_flow_set)
|
|
|
|
+ self.equipment.supply_air_flow_set = supply_air_flow_set
|
|
|
|
+ self.equipment.virtual_target_temperature = temperature_set
|
|
|
|
+ self.equipment.virtual_realtime_temperature = temperature_realtime
|
|
|
|
+
|
|
|
|
+ return supply_air_flow_set
|
|
|
|
+
|
|
|
|
+ async def run(self):
|
|
|
|
+ temperature_set, temperature_realtime = await self.build_virtual_temperature()
|
|
|
|
+ await self.get_supply_air_flow_set(temperature_set, temperature_realtime)
|
|
|
|
+ self.equipment.running_status = True
|
|
|
|
+
|
|
|
|
+ def get_results(self):
|
|
|
|
+ return self.equipment
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+class VAVControllerV2(VAVController):
|
|
|
|
+
|
|
|
|
+ def __init__(self, equipment: VAVBox, weights: List[SpaceWeight], season: Season):
|
|
|
|
+ super(VAVControllerV2, self).__init__(equipment)
|
|
|
|
+ # self.equipment = equipment
|
|
|
|
+ self.weights = weights
|
|
|
|
+ self.season = season
|
|
|
|
+
|
|
|
|
+ async def build_virtual_temperature(self):
|
|
valid_spaces = []
|
|
valid_spaces = []
|
|
weights = []
|
|
weights = []
|
|
- for sp in self._equipment.spaces:
|
|
|
|
|
|
+ for sp in self.equipment.spaces:
|
|
if sp.realtime_temperature > 0.0 and sp.temperature_target > 0.0:
|
|
if sp.realtime_temperature > 0.0 and sp.temperature_target > 0.0:
|
|
valid_spaces.append(sp)
|
|
valid_spaces.append(sp)
|
|
for weight in self.weights:
|
|
for weight in self.weights:
|
|
@@ -95,58 +127,41 @@ class VAVController(EquipmentController):
|
|
virtual_target += sp.temperature_target * weight_dic.get(sp.id)
|
|
virtual_target += sp.temperature_target * weight_dic.get(sp.id)
|
|
virtual_realtime += sp.realtime_temperature * weight_dic.get(sp.id)
|
|
virtual_realtime += sp.realtime_temperature * weight_dic.get(sp.id)
|
|
except KeyError:
|
|
except KeyError:
|
|
- logger.error(f'{self._equipment.id} has wrong vav-space relation')
|
|
|
|
|
|
+ logger.error(f'{self.equipment.id} has wrong vav-space relation')
|
|
raise HTTPException(status_code=404, detail='This VAV box has wrong eq-sp relation')
|
|
raise HTTPException(status_code=404, detail='This VAV box has wrong eq-sp relation')
|
|
|
|
|
|
- self._equipment.virtual_target_temperature = virtual_target
|
|
|
|
- self._equipment.virtual_realtime_temperature = virtual_realtime
|
|
|
|
|
|
+ self.equipment.virtual_target_temperature = virtual_target
|
|
|
|
+ self.equipment.virtual_realtime_temperature = virtual_realtime
|
|
else:
|
|
else:
|
|
- self._equipment.virtual_target_temperature = np.NAN
|
|
|
|
- self._equipment.virtual_realtime_temperature = np.NAN
|
|
|
|
|
|
+ self.equipment.virtual_target_temperature = np.NAN
|
|
|
|
+ self.equipment.virtual_realtime_temperature = np.NAN
|
|
|
|
|
|
async def rectify(self) -> Tuple[float, float]:
|
|
async def rectify(self) -> Tuple[float, float]:
|
|
- for sp in self._equipment.spaces:
|
|
|
|
|
|
+ for sp in self.equipment.spaces:
|
|
if sp.realtime_temperature < min(23.0, sp.temperature_target):
|
|
if sp.realtime_temperature < min(23.0, sp.temperature_target):
|
|
if self.season == Season.heating:
|
|
if self.season == Season.heating:
|
|
- self._equipment.virtual_target_temperature = min(23.0, sp.temperature_target) + 0.5
|
|
|
|
- self._equipment.virtual_realtime_temperature = sp.realtime_temperature
|
|
|
|
|
|
+ self.equipment.virtual_target_temperature = min(23.0, sp.temperature_target) + 0.5
|
|
|
|
+ self.equipment.virtual_realtime_temperature = sp.realtime_temperature
|
|
break
|
|
break
|
|
elif sp.realtime_temperature > max(27.0, sp.temperature_target):
|
|
elif sp.realtime_temperature > max(27.0, sp.temperature_target):
|
|
if self.season == Season.cooling:
|
|
if self.season == Season.cooling:
|
|
- self._equipment.virtual_target_temperature = max(27.0, sp.temperature_target)
|
|
|
|
- self._equipment.virtual_realtime_temperature = sp.realtime_temperature
|
|
|
|
|
|
+ self.equipment.virtual_target_temperature = max(27.0, sp.temperature_target)
|
|
|
|
+ self.equipment.virtual_realtime_temperature = sp.realtime_temperature
|
|
break
|
|
break
|
|
|
|
|
|
- return self._equipment.virtual_target_temperature, self._equipment.virtual_realtime_temperature
|
|
|
|
-
|
|
|
|
- async def get_supply_air_flow_set(self) -> float:
|
|
|
|
- # await self.build_virtual_temperature_v2()
|
|
|
|
- # temperature_set, temperature_realtime = await self.rectify()
|
|
|
|
- temperature_set, temperature_realtime = await self.build_virtual_temperature_v1()
|
|
|
|
- if np.isnan(temperature_set) or np.isnan(temperature_realtime):
|
|
|
|
- supply_air_flow_set = 0.0
|
|
|
|
- else:
|
|
|
|
- temperature_supply = self._equipment.supply_air_temperature
|
|
|
|
- if np.isnan(temperature_supply):
|
|
|
|
- temperature_supply = 19.0
|
|
|
|
- supply_air_flow_set = self._equipment.supply_air_flow * ((temperature_supply - temperature_realtime)
|
|
|
|
- / (temperature_supply - temperature_set))
|
|
|
|
- supply_air_flow_set = max(self._equipment.supply_air_flow_lower_limit, supply_air_flow_set)
|
|
|
|
- supply_air_flow_set = min(self._equipment.supply_air_flow_upper_limit, supply_air_flow_set)
|
|
|
|
- self._equipment.supply_air_flow_set = supply_air_flow_set
|
|
|
|
-
|
|
|
|
- return supply_air_flow_set
|
|
|
|
|
|
+ return self.equipment.virtual_target_temperature, self.equipment.virtual_realtime_temperature
|
|
|
|
|
|
async def run(self):
|
|
async def run(self):
|
|
- await self.get_supply_air_flow_set()
|
|
|
|
- self._equipment.running_status = True
|
|
|
|
|
|
+ await self.build_virtual_temperature()
|
|
|
|
+ temperature_set, temperature_realtime = await self.rectify()
|
|
|
|
+ await self.get_supply_air_flow_set(temperature_set, temperature_realtime)
|
|
|
|
+ self.equipment.running_status = True
|
|
|
|
|
|
def get_results(self):
|
|
def get_results(self):
|
|
- return self._equipment
|
|
|
|
|
|
+ return self.equipment
|
|
|
|
|
|
|
|
|
|
-@logger.catch()
|
|
|
|
-async def get_vav_control_result(db: Session, project_id: str, equipment_id: str) -> VAVBox:
|
|
|
|
|
|
+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)
|
|
platform = DataPlatformService(client, project_id)
|
|
platform = DataPlatformService(client, project_id)
|
|
@@ -188,19 +203,38 @@ async def get_vav_control_result(db: Session, project_id: str, equipment_id: str
|
|
space = Space(**temp_space_params)
|
|
space = Space(**temp_space_params)
|
|
space_objects.append(space)
|
|
space_objects.append(space)
|
|
|
|
|
|
- temp_vav_params = {
|
|
|
|
|
|
+ vav_params = {
|
|
'id': equipment_id,
|
|
'id': equipment_id,
|
|
'spaces': space_objects,
|
|
'spaces': space_objects,
|
|
'supply_air_temperature': realtime_supply_air_temperature,
|
|
'supply_air_temperature': realtime_supply_air_temperature,
|
|
'supply_air_flow': realtime_supply_air_flow,
|
|
'supply_air_flow': realtime_supply_air_flow,
|
|
'supply_air_flow_lower_limit': lower_limit,
|
|
'supply_air_flow_lower_limit': lower_limit,
|
|
'supply_air_flow_upper_limit': upper_limit,
|
|
'supply_air_flow_upper_limit': upper_limit,
|
|
|
|
+ 'season': season
|
|
}
|
|
}
|
|
- vav = VAVBox(**temp_vav_params)
|
|
|
|
|
|
|
|
|
|
+ return vav_params
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+@logger.catch()
|
|
|
|
+async def get_vav_control_v1(project: str, equipment_id: str) -> VAVBox:
|
|
|
|
+ vav_params = await fetch_vav_control_params(project, equipment_id)
|
|
|
|
+ vav = VAVBox(**vav_params)
|
|
|
|
+
|
|
|
|
+ vav_controller = VAVController(vav)
|
|
|
|
+ await vav_controller.run()
|
|
|
|
+ regulated_vav = vav_controller.get_results()
|
|
|
|
+
|
|
|
|
+ return regulated_vav
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+@logger.catch()
|
|
|
|
+async def get_vav_control_v2(db: Session, project_id: str, equipment_id: str) -> VAVBox:
|
|
|
|
+ vav_params = await fetch_vav_control_params(project_id, equipment_id)
|
|
|
|
+ vav = VAVBox(**vav_params)
|
|
weights = get_weights_by_vav(db, equipment_id)
|
|
weights = get_weights_by_vav(db, equipment_id)
|
|
|
|
|
|
- vav_controller = VAVController(vav, [SpaceWeight.from_orm(weight) for weight in weights], season)
|
|
|
|
|
|
+ vav_controller = VAVControllerV2(vav, [SpaceWeight.from_orm(weight) for weight in weights], vav_params['season'])
|
|
await vav_controller.run()
|
|
await vav_controller.run()
|
|
regulated_vav = vav_controller.get_results()
|
|
regulated_vav = vav_controller.get_results()
|
|
|
|
|