Skip to content

Commit be57b6b

Browse files
author
Robert Schindler
committed
[schedy] Deprecated OVERLAY_REVERT_ON_NO_RESULT result marker
1 parent fae7887 commit be57b6b

File tree

3 files changed

+66
-55
lines changed

3 files changed

+66
-55
lines changed

docs/apps/schedy/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
2020
### Changed
2121
* The `Skip` expression result type has been renamed to `Next`, which better describes
2222
its purpose.
23+
* The behaviour of the `OVERLAY_REVERT_ON_NO_RESULT` result marker now is the
24+
default with `OVERLAY`. The marker will be removed.
2325

2426
### Deprecated
2527
* 0.7: The previous name `Skip` for the `Next` expression result type will be removed.
28+
* 0.7: The `OVERLAY_REVERT_ON_NO_RESULT` marker will be removed, it's the default now.
2629

2730
### Removed
2831

docs/apps/schedy/schedules/expressions/result-markers.rst

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ The following markers are available:
3737
An occasion for using this marker is
3838
:doc:`../../tips-and-tricks/open-window-detection`.
3939

40-
* ``OVERLAY_REVERT_ON_NO_RESULT``: When applied in conjunction with the
41-
``OVERLAY`` marker, the overlay is cancelled as soon as a schedule
42-
evaluation produces no result (e.g. because ``Abort()`` was used). When
43-
an overlay is created without this additional marker, the value marked
44-
with ``OVERLAY`` stays active until the schedule really results in
45-
another value.
40+
* ``OVERLAY_REVERT_ON_NO_RESULT``: When applied in conjunction with the ``OVERLAY``
41+
marker, the overlay is cancelled as soon as a schedule evaluation produces no result
42+
(e.g. because ``Abort()`` was used or all rules evaluated to ``Next()``). When an
43+
overlay is created without this additional marker, the value marked with ``OVERLAY``
44+
stays active until the schedule really results in another value.
45+
**DEPRECATED:** This is the default behaviour of `OVERLAY` now.

hass_apps/schedy/room.py

Lines changed: 57 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,10 @@ def __init__(self, name: str, cfg: dict, app: "SchedyApp") -> None:
7575
self._scheduled_value = None # type: T.Any
7676
self._rescheduling_time = None # type: T.Optional[datetime.datetime]
7777
self._rescheduling_timer = None # type: T.Optional[uuid.UUID]
78+
self._overlay_active = False
7879
self._overlaid_wanted_value = None # type: T.Any
7980
self._overlaid_scheduled_value = None # type: T.Any
8081
self._overlaid_rescheduling_time = None # type: T.Optional[datetime.datetime]
81-
self._overlay_revert_on_no_result = None # type: T.Optional[bool]
8282

8383
self._last_state = None # type: T.Optional[T.Tuple[str, T.Dict[str, T.Any]]]
8484

@@ -97,10 +97,10 @@ def __str__(self) -> str:
9797
def _clear_overlay(self) -> None:
9898
"""Removes all stored overlay state."""
9999

100+
self._overlay_active = False
100101
self._overlaid_wanted_value = None
101102
self._overlaid_scheduled_value = None
102103
self._overlaid_rescheduling_time = None
103-
self._overlay_revert_on_no_result = None
104104

105105
@sync_proxy
106106
def _initialize_actor_cb(self, kwargs: dict) -> None:
@@ -164,6 +164,7 @@ def _deserialize_dt(value: T.Any) -> T.Optional[datetime.datetime]:
164164
self._wanted_value = _deserialize(state.get("state") or None)
165165
self._scheduled_value = _deserialize(attrs.get("scheduled_value"))
166166
self._rescheduling_time = _deserialize_dt(attrs.get("rescheduling_time"))
167+
self._overlay_active = attrs.get("overlay_active") or False
167168
self._overlaid_wanted_value = _deserialize(
168169
attrs.get("overlaid_wanted_value")
169170
)
@@ -173,7 +174,6 @@ def _deserialize_dt(value: T.Any) -> T.Optional[datetime.datetime]:
173174
self._overlaid_rescheduling_time = _deserialize_dt(
174175
attrs.get("overlaid_rescheduling_time")
175176
)
176-
self._overlay_revert_on_no_result = attrs.get("overlay_revert_on_no_result")
177177

178178
if self._rescheduling_time:
179179
if self._rescheduling_time > self.app.datetime():
@@ -210,30 +210,22 @@ def _state_entity_id(self) -> str:
210210

211211
return "schedy_room.{}_{}".format(self.app.name, self.name)
212212

213-
def _store_for_overlaying(self, scheduled_value: T.Any) -> bool:
213+
def _store_for_overlaying(self) -> None:
214214
"""This method is called before a value overlay is put into place.
215-
When a re-scheduling timer is running or the scheduled and
216-
wanted values differ, this method stores the scheduled and wanted
217-
value together with the re-scheduling time to later be able to
218-
re-set it.
219-
Everything except scheduled_value is fetched from self._*.
220-
A running re-scheduling timer is cancelled.
221-
If there already is an overlaid value stored, this does nothing.
222-
Returns whether values have been stored."""
223-
224-
if self._overlaid_wanted_value is None and (
225-
scheduled_value != self._wanted_value or self._rescheduling_timer
226-
):
227-
self.log(
228-
"Storing currently wanted value {} before an overlay "
229-
"is applied.".format(repr(self._wanted_value))
230-
)
231-
self._overlaid_wanted_value = self._wanted_value
232-
self._overlaid_scheduled_value = scheduled_value
233-
self._overlaid_rescheduling_time = self._rescheduling_time
234-
self.cancel_rescheduling_timer()
235-
return True
236-
return False
215+
It stores the scheduled and wanted value together with the re-scheduling
216+
time for later restoration. A running re-scheduling timer is cancelled.
217+
If an overlay is active already, this does nothing."""
218+
219+
if self._overlay_active:
220+
# Don't overwrite existing restoration records
221+
return
222+
223+
self.log("Storing value {!r} before overlaying.".format(self._wanted_value))
224+
self._overlay_active = True
225+
self._overlaid_wanted_value = self._wanted_value
226+
self._overlaid_scheduled_value = self._scheduled_value
227+
self._overlaid_rescheduling_time = self._rescheduling_time
228+
self.cancel_rescheduling_timer()
237229

238230
def _update_state(self) -> None:
239231
"""Update the room's state in Home Assistant."""
@@ -263,6 +255,7 @@ def _maybe_add(key: str, value: T.Any) -> None:
263255
},
264256
"scheduled_value": _serialize(self._scheduled_value, None),
265257
"rescheduling_time": _serialize_dt(self._rescheduling_time),
258+
"overlay_active": self._overlay_active,
266259
} # type: T.Dict[str, T.Any]
267260
_maybe_add(
268261
"overlaid_wanted_value", _serialize(self._overlaid_wanted_value, None)
@@ -274,7 +267,6 @@ def _maybe_add(key: str, value: T.Any) -> None:
274267
"overlaid_rescheduling_time",
275268
_serialize_dt(self._overlaid_rescheduling_time),
276269
)
277-
_maybe_add("overlay_revert_on_no_result", self._overlay_revert_on_no_result)
278270
_maybe_add("friendly_name", self.cfg.get("friendly_name"))
279271

280272
unchanged = (state, attrs) == self._last_state
@@ -325,15 +317,32 @@ def apply_schedule(self, reset: bool = False, force_resend: bool = False) -> Non
325317

326318
def _restore_overlaid_value() -> bool:
327319
"""Restores and clears an overlaid value.
328-
Returns whether a value has actually been set or not."""
320+
Returns whether a value has actually been restored or not."""
329321

330322
overlaid_wanted_value = self._overlaid_wanted_value
331-
delay = None # type: T.Union[None, datetime.datetime]
332-
if (
333-
self._overlaid_rescheduling_time
334-
and self._overlaid_rescheduling_time > self.app.datetime()
335-
):
323+
if overlaid_wanted_value is None:
324+
self.log(
325+
"Overlay ended but knowing no value to restore.", level="WARNING"
326+
)
327+
self._clear_overlay()
328+
return False
329+
330+
delay = None # type: T.Union[None, int, datetime.datetime]
331+
if not self._overlaid_rescheduling_time:
332+
if new_scheduled_value == self._overlaid_scheduled_value:
333+
# Scheduled value hasn't changed compared to before overlay,
334+
# hence revert to overlaid wanted value without timer
335+
delay = 0
336+
elif self._overlaid_rescheduling_time > self.app.datetime():
337+
# Resume overlaid re-scheduling timer
336338
delay = self._overlaid_rescheduling_time
339+
else:
340+
self.log(
341+
"Overlaid value {!r} has expired, not restoring it.".format(
342+
overlaid_wanted_value
343+
)
344+
)
345+
337346
self._clear_overlay()
338347
if delay is None:
339348
return False
@@ -355,30 +364,28 @@ def _restore_overlaid_value() -> bool:
355364
result = self.schedule.evaluate(self, self.app.datetime())
356365
if result is None:
357366
self.log("No suitable value found in schedule.", level="DEBUG")
358-
if self._overlay_revert_on_no_result:
359-
self._scheduled_value = self._overlaid_scheduled_value
367+
# revert an eventual overlay
368+
if self._overlay_active:
369+
new_scheduled_value = self._overlaid_scheduled_value
360370
_restore_overlaid_value()
371+
self._scheduled_value = new_scheduled_value
361372
return
362373

363-
value, markers = result[:2]
364-
if value == self._scheduled_value and not reset and not force_resend:
374+
new_scheduled_value, markers = result[:2]
375+
if not (new_scheduled_value != self._scheduled_value or reset or force_resend):
365376
self.log("Result didn't change, not setting it again.", level="DEBUG")
366377
return
367378

368-
previous_scheduled_value = self._scheduled_value
369-
self._scheduled_value = value
370-
371379
if reset:
372380
self.cancel_rescheduling_timer()
373381
self._clear_overlay()
374382
elif expression.types.Mark.OVERLAY in markers:
375-
self._store_for_overlaying(previous_scheduled_value)
376-
self._overlay_revert_on_no_result = (
377-
expression.types.Mark.OVERLAY_REVERT_ON_NO_RESULT in markers
378-
)
379-
elif self._overlaid_wanted_value is not None:
380-
if _restore_overlaid_value():
381-
return
383+
# Create restoration records if overlay not active already
384+
self._store_for_overlaying()
385+
# No overlay should be set, hence try to revert an existing one
386+
elif self._overlay_active and _restore_overlaid_value():
387+
self._scheduled_value = new_scheduled_value
388+
return
382389
elif self._rescheduling_timer:
383390
self.log(
384391
"Not applying the schedule now due to a running "
@@ -387,7 +394,8 @@ def _restore_overlaid_value() -> bool:
387394
)
388395
return
389396

390-
self.set_value(value, force_resend=force_resend)
397+
self._scheduled_value = new_scheduled_value
398+
self.set_value(new_scheduled_value, force_resend=force_resend)
391399

392400
def cancel_rescheduling_timer(self) -> bool:
393401
"""Cancels the re-scheduling timer for this room, if one
@@ -640,7 +648,7 @@ def set_value_manually(
640648
return
641649

642650
if expression.types.Mark.OVERLAY in markers:
643-
self._store_for_overlaying(self._scheduled_value)
651+
self._store_for_overlaying()
644652

645653
self.set_value(value, force_resend=force_resend)
646654
if rescheduling_delay != 0:

0 commit comments

Comments
 (0)