|
2 | 2 |
|
3 | 3 | # Standard Libraries |
4 | 4 | import logging |
5 | | -from typing import Any, Final |
| 5 | +from typing import Any, Final, Protocol |
6 | 6 |
|
7 | 7 | # Custom Modules |
8 | 8 | from config import ( |
|
13 | 13 | GRID_OUTAGE_TARGET_MODE, |
14 | 14 | EnergyMode |
15 | 15 | ) |
| 16 | +from energy_mode_control.mode_decision import decide_target_mode |
16 | 17 | from energy_mode_control.time_utils import is_time_reached |
17 | | -from energy_mode_control.energy_mode_switcher import ( |
18 | | - switch_energy_mode, |
19 | | -) |
20 | 18 |
|
21 | 19 |
|
22 | 20 | LOGGER = logging.getLogger(__name__) |
|
26 | 24 | GRID_OUTAGE_VOLTAGE_THRESHOLD: Final[float] = 10.0 |
27 | 25 |
|
28 | 26 |
|
29 | | -def handle_energy_mode_control(must_data: dict[str, Any] | None) -> bool: |
| 27 | +class InverterClient(Protocol): |
| 28 | + def switch_energy_mode(self, target_mode: EnergyMode) -> None: |
| 29 | + """Switch the inverter to the requested energy mode.""" |
| 30 | + |
| 31 | + |
| 32 | +def handle_energy_mode_control( |
| 33 | + must_data: dict[str, Any] | None, |
| 34 | + inverter_client: InverterClient, |
| 35 | +) -> bool: |
30 | 36 | try: |
31 | | - return _handle_energy_mode_control(must_data) |
| 37 | + return _handle_energy_mode_control(must_data, inverter_client) |
32 | 38 | except Exception: |
33 | 39 | LOGGER.exception("Failed to handle energy mode control.") |
34 | 40 | return False |
35 | 41 |
|
36 | 42 |
|
37 | | -def _handle_energy_mode_control(must_data: dict[str, Any] | None) -> bool: |
| 43 | +def _handle_energy_mode_control( |
| 44 | + must_data: dict[str, Any] | None, |
| 45 | + inverter_client: InverterClient, |
| 46 | +) -> bool: |
38 | 47 | if not ENABLE_AUTO_SWITCH and not ENABLE_GRID_OUTAGE_AUTO_SWITCH: |
39 | 48 | LOGGER.debug("All automatic energy mode control features are disabled.") |
40 | 49 | return False |
@@ -76,46 +85,51 @@ def _handle_energy_mode_control(must_data: dict[str, Any] | None) -> bool: |
76 | 85 | grid_voltage >= GRID_OUTAGE_VOLTAGE_THRESHOLD |
77 | 86 | ) |
78 | 87 |
|
79 | | - target_mode: EnergyMode | None = None |
80 | | - switch_reason: str | None = None |
81 | | - |
82 | | - # Grid outage rule has the highest priority. |
83 | | - if ( |
84 | | - ENABLE_GRID_OUTAGE_AUTO_SWITCH |
85 | | - and not is_grid_available |
86 | | - ): |
87 | | - target_mode = GRID_OUTAGE_TARGET_MODE |
88 | | - switch_reason = "electrical grid is unavailable" |
89 | | - |
90 | | - # Time-based rule is checked when the grid is available. |
91 | | - elif ( |
| 88 | + is_auto_switch_time_reached = ( |
92 | 89 | ENABLE_AUTO_SWITCH |
93 | 90 | and is_grid_available |
94 | 91 | and is_time_reached(AUTO_SWITCH_TARGET_TIME) |
95 | | - ): |
96 | | - target_mode = AUTO_SWITCH_TARGET_MODE |
97 | | - switch_reason = "auto-switch target time has been reached" |
| 92 | + ) |
| 93 | + target_mode = decide_target_mode( |
| 94 | + is_grid_available=is_grid_available, |
| 95 | + is_auto_switch_enabled=ENABLE_AUTO_SWITCH, |
| 96 | + is_auto_switch_time_reached=is_auto_switch_time_reached, |
| 97 | + auto_switch_target_mode=AUTO_SWITCH_TARGET_MODE, |
| 98 | + is_grid_outage_auto_switch_enabled=( |
| 99 | + ENABLE_GRID_OUTAGE_AUTO_SWITCH |
| 100 | + ), |
| 101 | + grid_outage_target_mode=GRID_OUTAGE_TARGET_MODE, |
| 102 | + ) |
| 103 | + |
| 104 | + return execute_mode_decision( |
| 105 | + current_mode=current_energy_mode, |
| 106 | + target_mode=target_mode, |
| 107 | + inverter_client=inverter_client, |
| 108 | + ) |
| 109 | + |
| 110 | + |
| 111 | +def execute_mode_decision( |
| 112 | + current_mode: EnergyMode, |
| 113 | + target_mode: EnergyMode | None, |
| 114 | + inverter_client: InverterClient, |
| 115 | +) -> bool: |
| 116 | + """Execute a mode decision when the target differs from current mode.""" |
98 | 117 |
|
99 | 118 | if target_mode is None: |
100 | 119 | LOGGER.debug("No energy mode switch is currently required.") |
101 | 120 | return False |
102 | 121 |
|
103 | | - if current_energy_mode == target_mode: |
| 122 | + if current_mode == target_mode: |
104 | 123 | LOGGER.debug( |
105 | 124 | "Inverter is already operating in %s mode.", |
106 | 125 | target_mode.name, |
107 | 126 | ) |
108 | 127 | return False |
109 | 128 |
|
110 | 129 | LOGGER.info( |
111 | | - "Energy mode switch required: %s -> %s. Reason: %s.", |
112 | | - current_energy_mode.name, |
| 130 | + "Energy mode switch required: %s -> %s.", |
| 131 | + current_mode.name, |
113 | 132 | target_mode.name, |
114 | | - switch_reason, |
115 | | - ) |
116 | | - |
117 | | - # The real inverter command will be added here: |
118 | | - switch_energy_mode( |
119 | | - target_mode=target_mode, |
120 | 133 | ) |
| 134 | + inverter_client.switch_energy_mode(target_mode=target_mode) |
121 | 135 | return True |
0 commit comments