Skip to content

Commit 61a4f66

Browse files
Move blocking feature of BatteryStatusTracker into separate class
In the future commit blocking will be only in BatteryStatusTracker. All blocking related public functions will be removed. Signed-off-by: ela-kotulska-frequenz <[email protected]>
1 parent 291f3b2 commit 61a4f66

File tree

1 file changed

+68
-37
lines changed

1 file changed

+68
-37
lines changed

src/frequenz/sdk/microgrid/_battery/_status.py

Lines changed: 68 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,68 @@ class _ComponentData(Generic[T]):
5151
receiver: Peekable[T]
5252

5353

54+
@dataclass
55+
class _BlockingStatus:
56+
min_duration_sec: float
57+
max_duration_sec: float
58+
59+
def __post_init__(self):
60+
self.last_blocking_duration_sec: float = self.min_duration_sec
61+
self.blocked_until: Optional[datetime] = None
62+
63+
def block(self) -> float:
64+
"""Block battery.
65+
66+
Battery can be unblocked using `self.unblock()` method.
67+
68+
Returns:
69+
For how long (in seconds) the battery is blocked.
70+
"""
71+
now = datetime.now(tz=timezone.utc)
72+
73+
# If is not blocked
74+
if self.blocked_until is None:
75+
self.last_blocking_duration_sec = self.min_duration_sec
76+
self.blocked_until = now + timedelta(
77+
seconds=self.last_blocking_duration_sec
78+
)
79+
return self.last_blocking_duration_sec
80+
81+
# If still blocked, then do nothing
82+
if self.blocked_until > now:
83+
return 0.0
84+
85+
# If previous blocking time expired, then blocked it once again.
86+
# Increase last blocking time, unless it reach the maximum.
87+
self.last_blocking_duration_sec = min(
88+
2 * self.last_blocking_duration_sec, self.max_duration_sec
89+
)
90+
self.blocked_until = now + timedelta(seconds=self.last_blocking_duration_sec)
91+
92+
return self.last_blocking_duration_sec
93+
94+
def unblock(self):
95+
"""Unblock battery.
96+
97+
This will reset duration of the next blocking timeout.
98+
99+
Battery can be blocked using `self.block()` method.
100+
"""
101+
self.blocked_until = None
102+
103+
def is_blocked(self) -> bool:
104+
"""Return if battery is blocked.
105+
106+
Battery can be blocked if last request for that battery failed.
107+
108+
Returns:
109+
True if battery is blocked, False otherwise.
110+
"""
111+
if self.blocked_until is None:
112+
return False
113+
return self.blocked_until > datetime.now(tz=timezone.utc)
114+
115+
54116
class BatteryStatusTracker(AsyncConstructible):
55117
"""Class for tracking if battery is working.
56118
@@ -79,10 +141,7 @@ class BatteryStatusTracker(AsyncConstructible):
79141
_battery_id: int
80142
_max_data_age: float
81143
_last_status: BatteryStatus
82-
_min_blocking_duration_sec: float
83-
_max_blocking_duration_sec: float
84-
_blocked_until: Optional[datetime]
85-
_last_blocking_duration_sec: float
144+
_blocking_status: _BlockingStatus
86145
_battery: _ComponentData[BatteryData]
87146
_inverter: _ComponentData[InverterData]
88147

@@ -112,10 +171,7 @@ async def async_new(
112171

113172
self._last_status = BatteryStatus.WORKING
114173

115-
self._min_blocking_duration_sec = 1.0
116-
self._max_blocking_duration_sec = max_blocking_duration_sec
117-
self._blocked_until = None
118-
self._last_blocking_duration_sec = self._min_blocking_duration_sec
174+
self._blocking_status = _BlockingStatus(1.0, max_blocking_duration_sec)
119175

120176
inverter_id = self._find_adjacent_inverter_id(battery_id)
121177
if inverter_id is None:
@@ -200,9 +256,7 @@ def is_blocked(self) -> bool:
200256
Returns:
201257
True if battery is blocked, False otherwise.
202258
"""
203-
if self._blocked_until is None:
204-
return False
205-
return self._blocked_until > datetime.now(tz=timezone.utc)
259+
return self._blocking_status.is_blocked()
206260

207261
def unblock(self) -> None:
208262
"""Unblock battery.
@@ -211,7 +265,7 @@ def unblock(self) -> None:
211265
212266
Battery can be blocked using `self.block()` method.
213267
"""
214-
self._blocked_until = None
268+
self._blocking_status.unblock()
215269

216270
def block(self) -> float:
217271
"""Block battery.
@@ -221,26 +275,7 @@ def block(self) -> float:
221275
Returns:
222276
For how long (in seconds) the battery is blocked.
223277
"""
224-
now = datetime.now(tz=timezone.utc)
225-
226-
if self._blocked_until is None:
227-
self._last_blocking_duration_sec = self._min_blocking_duration_sec
228-
self._blocked_until = now + timedelta(
229-
seconds=self._last_blocking_duration_sec
230-
)
231-
return self._last_blocking_duration_sec
232-
233-
# If still blocked, then do nothing
234-
if self._blocked_until > now:
235-
return 0.0
236-
237-
# Increase blocking duration twice or until it reach the max.
238-
self._last_blocking_duration_sec = min(
239-
2 * self._last_blocking_duration_sec, self._max_blocking_duration_sec
240-
)
241-
self._blocked_until = now + timedelta(seconds=self._last_blocking_duration_sec)
242-
243-
return self._last_blocking_duration_sec
278+
return self._blocking_status.block()
244279

245280
@property
246281
def blocked_until(self) -> Optional[datetime]:
@@ -250,11 +285,7 @@ def blocked_until(self) -> Optional[datetime]:
250285
Timestamp when the battery will be unblocked. Return None if battery is
251286
not blocked.
252287
"""
253-
if self._blocked_until is None or self._blocked_until < datetime.now(
254-
tz=timezone.utc
255-
):
256-
return None
257-
return self._blocked_until
288+
return self._blocking_status.blocked_until
258289

259290
def _no_critical_error(self, msg: Union[BatteryData, InverterData]) -> bool:
260291
"""Check if battery or inverter message has any critical error.

0 commit comments

Comments
 (0)