Browse Source

completed data jointing for equipment controller

chenhaiyang 4 years ago
parent
commit
746db5dc12

+ 36 - 0
app/api/routers/equipment.py

@@ -0,0 +1,36 @@
+# -*- coding: utf-8 -*-
+
+from enum import Enum
+
+from fastapi import APIRouter, HTTPException, Query
+from loguru import logger
+
+from app.controllers.equipment.vav import VAVController
+from app.models.equipment import EquipmentControlInResponse
+from app.utils.date import get_time_str
+
+
+class EquipmentName(str, Enum):
+    FCU = 'ATFC'
+    VAV = 'ATVA'
+
+
+router = APIRouter()
+
+
+@router.get('/control', response_model=EquipmentControlInResponse, tags=['equipment'])
+async def get_equipment_command(
+        projectId: str = Query(..., max_length=50, regex='^Pj'),
+        equipId: str = Query(..., max_length=50, regex='^Eq'),
+        equipType: EquipmentName = Query(...),
+        method: int = Query(3),
+):
+    response = {
+        'projectId': projectId,
+        'equipId': equipId,
+        'method': method,
+        'flag': 1,
+        'time': get_time_str(),
+        'output': {}
+    }
+    return response

+ 25 - 0
app/api/routers/space.py

@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+
+from fastapi import APIRouter, HTTPException, Query
+from loguru import logger
+
+from app.models.space import SpaceControlInResponse
+
+router = APIRouter()
+
+
+@router.get('/control', response_model=SpaceControlInResponse, tags=['space'])
+async def get_space_command(
+        projectId: str = Query(..., max_length=50, regex='^Pj'),
+        roomId: str = Query(..., max_length=50, regex='^Sp'),
+        time: str = Query(None, min_length=14, max_length=14),
+        method: int = Query(3),
+):
+    response = {
+        'projectId': projectId,
+        'roomId': roomId,
+        'flag': 1,
+        'time': time,
+        'method': method,
+    }
+    return response

+ 35 - 1
app/controllers/equipment/fcu.py

@@ -1,9 +1,14 @@
 # -*- coding: utf-8 -*-
 
 import numpy as np
+from httpx import AsyncClient
+from loguru import logger
 
 from app.controllers.equipment.controller import EquipmentController
-from app.models.equipment import FCU, AirValveSpeed
+from app.models.equipment import AirValveSpeed
+from app.models.equipment import FCU
+from app.models.space import Space
+from app.services.transfer import SpaceInfoService, EquipmentInfoService
 
 
 class FCUController(EquipmentController):
@@ -32,6 +37,35 @@ class FCUController(EquipmentController):
     async def run(self):
         await self.get_temperature_target()
         await self.get_air_valve_speed()
+        self._equipment.running_status = True
 
     def get_results(self):
         return self._equipment
+
+
+@logger.catch()
+async def get_fcu_control_result(project_id: str, equipment_id: str) -> FCU:
+    async with AsyncClient() as client:
+        duo_duo = EquipmentInfoService(client, project_id)
+        spaces = await duo_duo.get_space_by_equipment(equipment_id)
+        for sp in spaces:
+            transfer = SpaceInfoService(client, project_id, sp.get('id'))
+            current_target = await transfer.get_current_temperature_target()
+            temp_space_params = {
+                'id': sp.get('id'),
+                'temperature_target': current_target
+            }
+            space = Space(**temp_space_params)
+            break
+
+        fcu_temp_params = {
+            'id': equipment_id,
+            'space': space
+        }
+        fcu = FCU(**fcu_temp_params)
+
+    fcu_controller = FCUController(fcu)
+    await fcu_controller.run()
+    regulated_fcu = fcu_controller.get_results()
+
+    return regulated_fcu

+ 90 - 11
app/controllers/equipment/vav.py

@@ -1,9 +1,16 @@
 # -*- coding: utf-8 -*-
 
+from typing import Tuple
+
 import numpy as np
+from httpx import AsyncClient
+from loguru import logger
 
 from app.controllers.equipment.controller import EquipmentController
 from app.models.equipment import VAVBox, FCU
+from app.models.space import Space
+from app.services.platform import DataPlatformService
+from app.services.transfer import EquipmentInfoService, SpaceInfoService
 
 
 class VAVController(EquipmentController):
@@ -22,24 +29,96 @@ class VAVController(EquipmentController):
 
         return strategy
 
-    async def get_temperature_target(self) -> float:
-        total_targets = []
-        total_buffer = []
+    async def get_temperature(self) -> Tuple[float, float]:
+        target_list, realtime_list = [], []
+        buffer_list = []
         strategy = self.get_strategy()
         for space in self._equipment.spaces:
             if strategy == 'Plan A':
-                total_targets.append(space.temperature_target)
+                target_list.append(space.temperature_target)
+                realtime_list.append(space.realtime_temperature)
             elif strategy == 'Plan B':
                 for eq in space.equipment:
                     if isinstance(eq, FCU):
                         buffer = (4 - eq.air_valve_speed) / 4
-                        total_buffer.append(buffer)
+                        buffer_list.append(buffer)
                         break
-        total = total_buffer + total_targets
-        result = np.array(total).sum() / len(total_targets)
-        self._equipment.setting_temperature = result
+        total_target = buffer_list + target_list
+        total_realtime = buffer_list + realtime_list
+        target_result = np.array(total_target).sum() / len(target_list)
+        realtime_result = np.array(total_realtime).sum() / len(realtime_list)
+        self._equipment.setting_temperature = target_result
+
+        return target_result, realtime_result
+
+    async def get_supply_air_flow_set(self) -> float:
+        temperature_set, temperature_realtime = self.get_temperature()
+        temperature_supply = self._equipment.supply_air_temperature
+        supply_air_flow_set = self._equipment.supply_air_flow * ((temperature_supply - temperature_set)
+                                                                 / (temperature_supply - temperature_realtime))
+        self._equipment.supply_air_flow_set = supply_air_flow_set
+
+        return supply_air_flow_set
+
+    async def run(self):
+        await self.get_supply_air_flow_set()
+        self._equipment.running_status = True
+
+    def get_results(self):
+        return self._equipment
+
+
+@logger.catch()
+async def get_vav_control_result(project_id: str, equipment_id: str) -> VAVBox:
+    async with AsyncClient() as client:
+        duo_duo = EquipmentInfoService(client, project_id)
+        platform = DataPlatformService(client, project_id)
+
+        _AHU_LIST = [
+            'Eq1101050030846e0a94670842109f7c8d8db0d44cf5',
+            'Eq1101050030b6b2f1db3d6944afa71e213e0d45d565'
+        ]
+        realtime_supply_air_temperature_list = []
+        for eq in _AHU_LIST:
+            realtime_supply_air_temperature_list.append(await platform.get_realtime_supply_air_temperature(eq))
+        realtime_supply_air_temperature = np.array(realtime_supply_air_temperature_list).mean()
+        realtime_supply_air_flow = await platform.get_realtime_supply_air_flow(equipment_id)
+
+        served_spaces = await duo_duo.get_space_by_equipment(equipment_id)
+        space_objects = []
+        for sp in served_spaces:
+            sp_id = sp.get('id')
+            transfer = SpaceInfoService(client, project_id, sp_id)
+            current_target = await transfer.get_current_temperature_target()
+            realtime_temperature = await platform.get_realtime_temperature(sp_id)
+
+            related_equipment = await transfer.get_equipment()
+            equipment_objects = []
+            for eq in related_equipment:
+                if eq.get('category') == 'ACATFC':
+                    speed = await platform.get_fan_speed(eq.get('id'))
+                    temp_fcu_params = {'id': eq.get('id'), 'air_valve_speed': speed}
+                    fcu = FCU(**temp_fcu_params)
+                    equipment_objects.append(fcu)
+            temp_space_params = {
+                'id': sp_id,
+                'realtime_temperature': realtime_temperature,
+                'equipment': equipment_objects,
+                'temperature_target': current_target
+            }
+            space = Space(**temp_space_params)
+            space_objects.append(space)
+
+        temp_vav_params = {
+            'id': equipment_id,
+            'spaces': space_objects,
+            'supply_air_temperature': realtime_supply_air_temperature,
+            'supply_air_flow': realtime_supply_air_flow,
+        }
+        vav = VAVBox(**temp_vav_params)
 
-        return result
+    vav_controller = VAVController(vav)
+    await vav_controller.run()
+    regulated_vav = vav_controller.get_results()
 
-    def run(self):
-        pass
+    return regulated_vav

+ 0 - 0
app/controllers/space/__init__.py


+ 3 - 1
app/main.py

@@ -8,7 +8,7 @@ import uvicorn
 from fastapi import FastAPI, Depends
 from loguru import logger
 
-from app.api.routers import targets
+from app.api.routers import targets, equipment, space
 from app.core.logger import InterceptHandler
 from app.core.config import LoggerSettings
 
@@ -19,6 +19,8 @@ logger.add(Path(logger_settings.logs_dir, 'env_fastapi.log'), level='INFO', rota
 app = FastAPI()
 
 app.include_router(targets.router, prefix='/target')
+app.include_router(space.router, prefix='/room')
+app.include_router(equipment.router, prefix='/equip')
 
 
 @lru_cache()

+ 15 - 15
app/models/equipment.py

@@ -25,21 +25,21 @@ class BaseEquipment(BaseModel):
 class FCU(BaseEquipment):
     air_valve_speed: Optional[AirValveSpeed] = AirValveSpeed.off
     water_valve_status: Optional[bool] = False
-    space: Space
+    space: Optional[Space]
 
 
 class VAVBox(BaseEquipment):
-    spaces: List[Space]
-
-
-if __name__ == '__main__':
-    external_data = {
-        'id': '123',
-        'running_status': True
-    }
-    fcu = FCU(**external_data)
-    print(fcu.id)
-    print(fcu.setting_temperature)
-    fcu.setting_temperature = 23.5
-    print(fcu.setting_temperature)
-    print(isinstance(fcu, FCU))
+    spaces: Optional[List[Space]]
+    supply_air_temperature: Optional[float]
+    supply_air_flow: Optional[float]
+    supply_air_flow_set: Optional[float]
+
+
+class EquipmentControlInResponse(BaseModel):
+    result: str = 'success'
+    projectId: str
+    equipId: str
+    method: int
+    flag: int
+    time: str
+    output: dict

+ 9 - 0
app/models/space.py

@@ -10,3 +10,12 @@ class Space(BaseModel):
     realtime_temperature: float
     equipment: List[str]
     temperature_target: float
+
+
+class SpaceControlInResponse(BaseModel):
+    result: str = 'success'
+    projectId: str
+    roomId: str
+    flag: int
+    time: str
+    method: int

+ 24 - 14
app/services/platform.py

@@ -22,6 +22,9 @@ class InfoCode(str, Enum):
     hcho = 'HCHO'
     pm2d5 = 'PM2d5'
     humidity = 'RH'
+    supply_air_flow = 'SupplyAirFlow'
+    supply_air_temperature = 'SupplyAirTemp'
+    fan_speed = 'FanGear'
 
 
 class DataPlatformService(Service):
@@ -30,12 +33,10 @@ class DataPlatformService(Service):
             self,
             client: AsyncClient,
             project_id: str,
-            space_id: str,
             settings: PlatformSettings = platform_settings
     ):
         super(DataPlatformService, self).__init__(client)
         self._project_id = project_id
-        self._space_id = space_id
         self._base_url = URL(settings.platform_host)
         self._now_time = get_time_str()
         self._secret = settings.platform_secret
@@ -43,13 +44,13 @@ class DataPlatformService(Service):
     def _common_parameters(self) -> Dict:
         return {'projectId': self._project_id, 'secret': self._secret}
 
-    async def get_realtime_data(self, code: InfoCode) -> float:
+    async def get_realtime_data(self, code: InfoCode, object_id: str) -> float:
         url = self._base_url.join('data-platform-3/hisdata/query_by_obj')
         params = self._common_parameters()
         start_time = get_time_str(60 * 60, flag='ago')
         payload = {
             'criteria': {
-                'id': self._space_id,
+                'id': object_id,
                 'code': code.value,
                 'receivetime': {
                     '$gte': start_time,
@@ -69,17 +70,26 @@ class DataPlatformService(Service):
 
         return value
 
-    async def get_realtime_temperature(self) -> float:
-        return await self.get_realtime_data(InfoCode.temperature)
+    async def get_realtime_temperature(self, space_id: str) -> float:
+        return await self.get_realtime_data(InfoCode.temperature, space_id)
 
-    async def get_realtime_co2(self) -> float:
-        return await self.get_realtime_data(InfoCode.co2)
+    async def get_realtime_co2(self, space_id: str) -> float:
+        return await self.get_realtime_data(InfoCode.co2, space_id)
 
-    async def get_realtime_hcho(self) -> float:
-        return await self.get_realtime_data(InfoCode.hcho)
+    async def get_realtime_hcho(self, space_id: str) -> float:
+        return await self.get_realtime_data(InfoCode.hcho, space_id)
 
-    async def get_realtime_pm2d5(self) -> float:
-        return await self.get_realtime_data(InfoCode.pm2d5)
+    async def get_realtime_pm2d5(self, space_id: str) -> float:
+        return await self.get_realtime_data(InfoCode.pm2d5, space_id)
 
-    async def get_realtime_humidity(self) -> float:
-        return await self.get_realtime_data(InfoCode.humidity)
+    async def get_realtime_humidity(self, space_id: str) -> float:
+        return await self.get_realtime_data(InfoCode.humidity, space_id)
+
+    async def get_realtime_supply_air_flow(self, equipment_id: str) -> float:
+        return await self.get_realtime_data(InfoCode.supply_air_flow, equipment_id)
+
+    async def get_realtime_supply_air_temperature(self, equipment_id: str) -> float:
+        return await self.get_realtime_data(InfoCode.supply_air_temperature, equipment_id)
+
+    async def get_fan_speed(self, equipment_id: str) -> float:
+        return await self.get_realtime_data(InfoCode.fan_speed, equipment_id)

+ 45 - 2
app/services/transfer.py

@@ -22,7 +22,7 @@ class Season(str, Enum):
     transition = 'Transition'
 
 
-class TransferService(Service):
+class SpaceInfoService(Service):
 
     def __init__(
             self,
@@ -31,7 +31,7 @@ class TransferService(Service):
             space_id: str,
             settings: TransferSettings = transfer_settings
     ) -> None:
-        super(TransferService, self).__init__(client)
+        super(SpaceInfoService, self).__init__(client)
         self._project_id = project_id
         self._space_id = space_id
         self._base_url = URL(settings.transfer_host)
@@ -114,6 +114,15 @@ class TransferService(Service):
 
         return custom_target_df
 
+    async def get_current_temperature_target(self) -> float:
+        current_targets = await self.get_custom_target()
+        temp = arrow.get(self._now_time, TIME_FMT).shift(minutes=15).timestamp // (15 * 60) * (15 * 60)
+        next_quarter_minutes = arrow.get(temp).time().strftime('%H%M%S')
+        current_lower_target = current_targets['temperatureMin'].loc[next_quarter_minutes]
+        current_upper_target = current_targets['temperatureMax'].loc[next_quarter_minutes]
+
+        return (current_lower_target + current_upper_target) / 2
+
     async def env_database_set(self, form: str, value: float) -> None:
         url = self._base_url.join('duoduo-service/transfer/environment/hispoint/set')
         params = self._common_parameters()
@@ -158,3 +167,37 @@ class TransferService(Service):
         params = self._common_parameters()
         params.update({'time': self._now_time})
         await self._get(url, params)
+
+    async def get_equipment(self) -> List[dict]:
+        url = self._base_url.join('duoduo-service/object-service/object/equipment/findForServe')
+        params = self._common_parameters()
+        raw_info = await self._post(url, params)
+
+        result = []
+        for eq in raw_info.get('data'):
+            result.append({'id': eq.get('id'), 'category': eq.get('equipmentCategory')})
+
+        return result
+
+
+class EquipmentInfoService(Service):
+
+    def __init__(self, client: AsyncClient, project_id: str, settings: TransferSettings = transfer_settings):
+        super(EquipmentInfoService, self).__init__(client)
+        self._project_id = project_id
+        self._base_url = URL(settings.transfer_host)
+        self._now_time = get_time_str()
+
+    async def get_space_by_equipment(self, equipment_id: str) -> List[dict]:
+        url = self._base_url.join('duoduo-service/object-service/object/space/findForServe')
+        params = {
+            'projectId': self._project_id,
+            'spaceId': equipment_id
+        }
+        raw_info = await self._post(url, params)
+
+        result = []
+        for sp in raw_info.get('data'):
+            result.append({'id': sp.get('id')})
+
+        return result