Przeglądaj źródła

update ATFC control logic

highing666 3 lat temu
rodzic
commit
4044d87960
2 zmienionych plików z 168 dodań i 23 usunięć
  1. 157 23
      app/controllers/equipment/fcu/basic.py
  2. 11 0
      app/models/domain/devices.py

+ 157 - 23
app/controllers/equipment/fcu/basic.py

@@ -10,7 +10,9 @@ from app.controllers.equipment.controller import EquipmentController
 from app.models.domain.devices import (
     ACATFC2InstructionsRequest,
     ACATFC4InstructionsRequest,
+    Speed,
 )
+from app.models.domain.feedback import FeedbackValue
 from app.schemas.equipment import AirValveSpeed, FCU
 from app.schemas.instructions import ACATFCInstructions
 from app.schemas.space import Space
@@ -182,15 +184,69 @@ class FCUControllerV2(EquipmentController):
         return self.equipment
 
 
+class SpeedController:
+    def __init__(self, current_speed: Speed, running_status: bool) -> None:
+        if running_status:
+            self.current_speed = current_speed
+        else:
+            self.current_speed = Speed.off
+        self.next_speed = current_speed
+
+    def turn_up(self) -> Speed:
+        if self.current_speed == Speed.off:
+            self.next_speed = Speed.low
+        elif self.current_speed == Speed.low:
+            self.next_speed = Speed.medium
+        elif self.current_speed == Speed.medium:
+            self.next_speed = Speed.high
+
+        return self.next_speed
+
+    def turn_down(self) -> Speed:
+        if self.current_speed == Speed.high:
+            self.next_speed = Speed.medium
+        elif self.current_speed == Speed.medium:
+            self.next_speed = Speed.low
+        elif self.current_speed == Speed.low:
+            self.next_speed = Speed.off
+
+        return self.next_speed
+
+    def turn_on(self) -> Speed:
+        self.next_speed = Speed.medium
+
+        return self.next_speed
+
+    def turn_off(self) -> Speed:
+        self.next_speed = Speed.off
+
+        return self.next_speed
+
+    def get_next_speed(self) -> Speed:
+        return self.next_speed
+
+
 class ATFC2Controller:
     """Two-wipe ATFC logic"""
 
-    def __init__(self, space_target: float, space_realtime: float, season: Season):
+    def __init__(
+        self,
+        space_target: float,
+        space_realtime: float,
+        season: Season,
+        feedback: FeedbackValue,
+        running_status: bool,
+        speed: Speed,
+    ):
         self.space_target = space_target
         self.space_realtime = space_realtime
         self.season = season
+        self.feedback = feedback
+        self.running_status = running_status
+        self.speed = speed
 
-    def build_speed_set(self) -> str:
+    def build_speed_set(self) -> Speed:
+        speed_controller = SpeedController(self.speed, self.running_status)
         if self.space_realtime > 0.0 and self.space_target > 0.0:
             if self.season == Season.cooling:
                 diff = self.space_realtime - self.space_target
@@ -199,24 +255,47 @@ class ATFC2Controller:
             else:
                 diff = 0.0
 
-            if diff <= 0.0:
-                speed = "off"
+            if diff <= -0.2:
+                speed = Speed.off
+            elif diff <= 0.2:
+                speed = Speed.hold
             elif diff < 0.5:
-                speed = "low"
+                speed = Speed.low
             elif diff < 1.5:
-                speed = "medium"
+                speed = Speed.medium
             else:
-                speed = "high"
+                speed = Speed.high
         else:
-            speed = "hold"
+            speed = Speed.hold
             if self.space_target < 0.0:
-                speed = "off"
+                speed = Speed.off
+            else:
+                if self.feedback == FeedbackValue.switch_on:
+                    speed = Speed.medium
+                elif (
+                    self.feedback == FeedbackValue.so_hot
+                    or self.feedback == FeedbackValue.a_little_hot
+                ):
+                    if self.season == Season.cooling:
+                        speed = speed_controller.turn_up()
+                    elif self.season == Season.heating:
+                        speed = speed_controller.turn_down()
+                elif (
+                    self.feedback == FeedbackValue.so_cold
+                    or self.feedback == FeedbackValue.a_little_cold
+                ):
+                    if self.season == Season.cooling:
+                        speed = speed_controller.turn_down()
+                    elif self.season == Season.heating:
+                        speed = speed_controller.turn_up()
 
         return speed
 
-    def build_switch_set(self, new_speed_set: str) -> str:
-        if new_speed_set == "off":
+    def build_switch_set(self, new_speed_set: Speed) -> str:
+        if new_speed_set == Speed.off:
             switch_set = "off"
+        elif new_speed_set == Speed.hold:
+            switch_set = "hold"
         else:
             switch_set = "on"
 
@@ -242,22 +321,49 @@ class ATFC2Controller:
 class ATFC4Controller(ATFC2Controller):
     """Four-wipe ATFC logic"""
 
-    def __init__(self, space_target: float, space_realtime: float, season: Season):
-        super().__init__(space_target, space_realtime, season)
+    def __init__(
+        self,
+        space_target: float,
+        space_realtime: float,
+        season: Season,
+        feedback: FeedbackValue,
+        running_status: bool,
+        speed: Speed,
+    ):
+        super().__init__(
+            space_target, space_realtime, season, feedback, running_status, speed
+        )
 
-    def build_speed_set(self) -> str:
+    def build_speed_set(self) -> Speed:
         speed = super().build_speed_set()
         if self.season == Season.heating:
+            speed_controller = SpeedController(self.speed, self.running_status)
             if self.space_target > 0.0 and self.space_realtime > 0.0:
                 diff = abs(self.space_realtime - self.space_target)
                 if diff < 0.2:
-                    speed = "off"
-                elif diff < 0.8:
-                    speed = "low"
+                    speed = Speed.hold
+                elif diff < 0.5:
+                    speed = Speed.low
                 elif diff < 1.5:
-                    speed = "medium"
+                    speed = Speed.medium
+                else:
+                    speed = Speed.high
+            else:
+                if self.space_target < 0.0:
+                    speed = Speed.off
                 else:
-                    speed = "high"
+                    if self.feedback == FeedbackValue.switch_on:
+                        speed = Speed.medium
+                    elif (
+                        self.feedback == FeedbackValue.so_hot
+                        or self.feedback == FeedbackValue.a_little_hot
+                    ):
+                        speed = speed_controller.turn_up()
+                    elif (
+                        self.feedback == FeedbackValue.so_cold
+                        or self.feedback == FeedbackValue.a_little_cold
+                    ):
+                        speed = speed_controller.turn_up()
 
         return speed
 
@@ -268,15 +374,33 @@ class ATFC4Controller(ATFC2Controller):
         else:
             if self.season == Season.heating:
                 if self.space_realtime > 0.0:
-                    if self.space_realtime > self.space_target:
+                    if self.space_realtime - self.space_target >= 0.2:
                         chill_water_valve_set = "on"
                         hot_water_valve_set = "off"
-                    else:
+                    elif self.space_target - self.space_realtime >= 0.2:
                         chill_water_valve_set = "off"
                         hot_water_valve_set = "on"
+                    else:
+                        chill_water_valve_set = "hold"
+                        hot_water_valve_set = "hold"
                 else:
                     chill_water_valve_set = "hold"
                     hot_water_valve_set = "hold"
+                    if self.feedback == FeedbackValue.switch_on:
+                        chill_water_valve_set = "off"
+                        hot_water_valve_set = "on"
+                    elif (
+                        self.feedback == FeedbackValue.so_hot
+                        or self.feedback == FeedbackValue.a_little_hot
+                    ):
+                        chill_water_valve_set = "on"
+                        hot_water_valve_set = "off"
+                    elif (
+                        self.feedback == FeedbackValue.so_cold
+                        or self.feedback == FeedbackValue.a_little_cold
+                    ):
+                        chill_water_valve_set = "off"
+                        hot_water_valve_set = "on"
             else:
                 chill_water_valve_set = "on"
                 hot_water_valve_set = "off"
@@ -411,7 +535,12 @@ async def build_acatfc2_instructions_v2(params: ACATFC2InstructionsRequest) -> d
         params.space_realtime_temperature if params.space_realtime_temperature else -1
     )
     controller = ATFC2Controller(
-        params.space_temperature_target, space_realtime, Season(params.season)
+        params.space_temperature_target,
+        space_realtime,
+        Season(params.season),
+        params.feedback,
+        params.running_status,
+        params.speed,
     )
     instructions = controller.run()
 
@@ -424,7 +553,12 @@ async def build_acatfc4_instructions_v2(params: ACATFC4InstructionsRequest) -> d
         params.space_realtime_temperature if params.space_realtime_temperature else -1
     )
     controller = ATFC4Controller(
-        params.space_temperature_target, space_realtime, Season(params.season)
+        params.space_temperature_target,
+        space_realtime,
+        Season(params.season),
+        params.feedback,
+        params.running_status,
+        params.speed,
     )
     instructions = controller.run()
 

+ 11 - 0
app/models/domain/devices.py

@@ -15,6 +15,14 @@ class ThermalMode(str, Enum):
     hold = "hold"
 
 
+class Speed(str, Enum):
+    off = 'off'
+    low = 'low'
+    medium = 'medium'
+    high = 'high'
+    hold = 'hold'
+
+
 class DevicesInstructionsBaseResponse(BaseModel):
     project_id: str = Field(None, alias="projectId")
     device_id: str = Field(None, alias="equipId")
@@ -57,6 +65,9 @@ class ACATFCInstructionsRequestBase(BaseModel):
     season: str
     space_temperature_target: float
     space_realtime_temperature: Optional[float]
+    running_status: bool
+    speed: Speed
+    feedback: FeedbackValue
 
 
 class ACATFC2InstructionsRequest(ACATFCInstructionsRequestBase):